| 1 | /**
|
|---|
| 2 | * De primitieven die iedereen die ActivityPub uitzendt nodig heeft.
|
|---|
| 3 | *
|
|---|
| 4 | * Waarom dit bestand er is (shaer-drc): ActivityPubService.js was 6436 regels
|
|---|
| 5 | * met 166 exports en tweeentwintig secties. Een submap zoals music/ kan pas
|
|---|
| 6 | * zelfstandig bestaan als deze zes dingen ergens staan waar BEIDE uit kunnen
|
|---|
| 7 | * putten -- anders importeert de submap uit ActivityPubService en importeert
|
|---|
| 8 | * die weer terug, en dat is een kring.
|
|---|
| 9 | *
|
|---|
| 10 | * Guardianship laat zien hoe het wel moet: die map importeert alleen db en zijn
|
|---|
| 11 | * eigen buren, nooit terug. Dit bestand maakt datzelfde mogelijk voor de rest.
|
|---|
| 12 | *
|
|---|
| 13 | * Alles hier is PUUR: geen database, geen netwerk, geen toestand. Dat is de
|
|---|
| 14 | * grens -- komt daar iets bij dat wel iets weet, dan hoort het hier niet.
|
|---|
| 15 | *
|
|---|
| 16 | * EEN UITZONDERING OP "PUUR": AP_CONTEXT stelt zichzelf samen uit
|
|---|
| 17 | * Guardianship.SHAER_CONTEXT. Die context is nu eenmaal de optelsom van ieders
|
|---|
| 18 | * termen, dus dat hoort zo. Het maakt geen kring: guardianship kent alleen db
|
|---|
| 19 | * en zijn eigen buren en importeert nooit terug.
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | import * as Guardianship from './guardianship/index.js';
|
|---|
| 23 |
|
|---|
| 24 | export const PUBLIC = 'https://www.w3.org/ns/activitystreams#Public';
|
|---|
| 25 | // Full JSON-LD context for every AP object we emit: AS2 core + security (publicKey) + the
|
|---|
| 26 | // extension terms we actually use (Mastodon/toot + schema.org), each with a term definition
|
|---|
| 27 | // so a strict JSON-LD processor resolves them instead of dropping them → valid AS2/JSON-LD.
|
|---|
| 28 | // This is the same context shape Mastodon publishes, so Mastodon sees no change.
|
|---|
| 29 | export const AP_CONTEXT = [
|
|---|
| 30 | 'https://www.w3.org/ns/activitystreams',
|
|---|
| 31 | 'https://w3id.org/security/v1',
|
|---|
| 32 | {
|
|---|
| 33 | toot: 'http://joinmastodon.org/ns#',
|
|---|
| 34 | schema: 'http://schema.org#',
|
|---|
| 35 | sensitive: 'as:sensitive',
|
|---|
| 36 | Hashtag: 'as:Hashtag',
|
|---|
| 37 | manuallyApprovesFollowers: 'as:manuallyApprovesFollowers',
|
|---|
| 38 | discoverable: 'toot:discoverable',
|
|---|
| 39 | // FEP-7628 (account moves): same term declaration Mastodon ships.
|
|---|
| 40 | alsoKnownAs: { '@id': 'as:alsoKnownAs', '@type': '@id' },
|
|---|
| 41 | movedTo: { '@id': 'as:movedTo', '@type': '@id' },
|
|---|
| 42 | featured: { '@id': 'toot:featured', '@type': '@id' },
|
|---|
| 43 | PropertyValue: 'schema:PropertyValue',
|
|---|
| 44 | value: 'schema:value',
|
|---|
| 45 | embedUrl: { '@id': 'schema:embedUrl', '@type': '@id' },
|
|---|
| 46 | // Wat een track beschrijft en AS2 niet kent (shaer-0nh). Funkwhale zet deze
|
|---|
| 47 | // vier op zijn Audio; het bleken geen eigen verzinsels maar termen die
|
|---|
| 48 | // schema.org gewoon heeft -- en schema.org stond hier al. De SLEUTELS zijn
|
|---|
| 49 | // die van Funkwhale, want daar leest hij op; de BETEKENIS komt van
|
|---|
| 50 | // schema.org, dus we hoeven geen vreemd vocabulaire binnen te halen.
|
|---|
| 51 | license: { '@id': 'schema:license', '@type': '@id' },
|
|---|
| 52 | position: 'schema:position',
|
|---|
| 53 | bitrate: 'schema:bitrate',
|
|---|
| 54 | size: 'schema:contentSize',
|
|---|
| 55 | // Poll (Question) extension: Question/oneOf/anyOf/endTime/closed are AS2 core, but the
|
|---|
| 56 | // per-poll unique-voter count is a Mastodon (toot) term — declare it so the emitted
|
|---|
| 57 | // Question stays valid JSON-LD (a strict processor would otherwise drop votersCount).
|
|---|
| 58 | votersCount: 'toot:votersCount',
|
|---|
| 59 | // Kanaal-vocabulaire (shaer-0nh). Funkwhale declareert `category` niet
|
|---|
| 60 | // inline maar via zijn eigen remote context https://funkwhale.audio/ns, en
|
|---|
| 61 | // die host is vanaf hier onbereikbaar -- de IRI hieronder is dus AFGELEID
|
|---|
| 62 | // en niet geverifieerd. Wat vandaag telt voor interop is de JSON-sleutel,
|
|---|
| 63 | // want daar matchen lezers op; de declaratie zorgt alleen dat een strikte
|
|---|
| 64 | // JSON-LD-processor hem niet laat vallen. Nakijken zodra die host weer
|
|---|
| 65 | // antwoordt.
|
|---|
| 66 | category: { '@id': 'https://funkwhale.audio/ns#category' },
|
|---|
| 67 | // FEP-633c (Guardians): the shaer namespace, owned by the guardianship
|
|---|
| 68 | // module (src/services/guardianship/).
|
|---|
| 69 | ...Guardianship.SHAER_CONTEXT,
|
|---|
| 70 | },
|
|---|
| 71 | ];
|
|---|
| 72 |
|
|---|
| 73 | /** Een absolute http(s)-URL, of leeg. De enige plek die bepaalt wat wij een
|
|---|
| 74 | * bruikbare URL vinden. */
|
|---|
| 75 | export const safeUrl = (u) => { const s = String(u == null ? '' : u).trim(); return /^https?:\/\//i.test(s) ? s : ''; };
|
|---|
| 76 |
|
|---|
| 77 | export function actorId(base, slug) { return `${base}/ap/users/${encodeURIComponent(slug)}`; }
|
|---|
| 78 | export function noteId(base, postId) { return `${base}/ap/notes/${encodeURIComponent(postId)}`; }
|
|---|
| 79 |
|
|---|
| 80 | /**
|
|---|
| 81 | * mediaType raden uit een bestandsnaam. Stond twee keer functie-lokaal in dit
|
|---|
| 82 | * bestand, met een commentaar dat ze "dezelfde afleiding" waren -- en dat was
|
|---|
| 83 | * niet zo: de ene kende video, de andere alleen beeld. Nu een kaart, hier.
|
|---|
| 84 | * De terugval is image/jpeg omdat dit alleen op omslagen en bijlagen wordt
|
|---|
| 85 | * losgelaten, nooit op geluid: dat draagt zijn eigen mime_type uit de database.
|
|---|
| 86 | */
|
|---|
| 87 | export function guessMediaType(u) {
|
|---|
| 88 | const e = ((u || '').split('?')[0].match(/\.(\w+)$/) || [])[1];
|
|---|
| 89 | return ({
|
|---|
| 90 | jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif',
|
|---|
| 91 | webp: 'image/webp', avif: 'image/avif',
|
|---|
| 92 | mp4: 'video/mp4', webm: 'video/webm', mov: 'video/quicktime',
|
|---|
| 93 | })[(e || '').toLowerCase()] || 'image/jpeg';
|
|---|
| 94 | }
|
|---|