Changeset 30871c1 in Klonkt
- Timestamp:
- 07/20/2026 11:35:45 PM (7 weeks ago)
- Branches:
- main
- Children:
- 562e1b0
- Parents:
- 5143ccf
- git-author:
- Robin <roboburr@…> (07/20/2026 11:35:44 PM)
- git-committer:
- Robin <roboburr@…> (07/20/2026 11:35:45 PM)
- Files:
-
- 4 edited
-
docs/shaer-c2s-api.md (modified) (1 diff)
-
src/routes/activitypub.js (modified) (3 diffs)
-
src/services/ActivityPubService.js (modified) (2 diffs)
-
test/c2s-contacts.test.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
docs/shaer-c2s-api.md
r5143ccf r30871c1 84 84 85 85 **Followers and following** are count-only for the public (privacy). With the 86 owner's bearer they return the real entries as AS2 actor references with display, 87 so a client shows names and avatars instead of bare ids: 86 owner's bearer they return the real entries. By default these are bare id 87 strings; send `Prefer: return=representation` (FEP-9876) to get them enriched as 88 AS2 actor references with display, so a client shows names and avatars instead of 89 bare ids. The server echoes `Preference-Applied: return=representation` and sets 90 `Vary: Prefer`: 88 91 89 92 ```json -
src/routes/activitypub.js
r5143ccf r30871c1 169 169 // URIs so their own client can build a friends list; everyone else gets the 170 170 // count only (privacy). 171 // FEP-9876: enrichment is opt-in via `Prefer: return=representation` (RFC 7240). 172 // Returns true and sets the response headers when the owner asked for it. 173 function wantsEnriched(req, res) { 174 res.set('Vary', 'Prefer'); // enriched and bare are two representations 175 if (AP.prefersEnriched(req.get('Prefer'))) { 176 res.set('Preference-Applied', 'return=representation'); 177 return true; 178 } 179 return false; 180 } 181 171 182 router.get('/ap/users/:slug/followers', (req, res) => { 172 183 const auth = OAuth.verifyBearer(req.headers.authorization); … … 176 187 if (owner) { 177 188 const uris = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? ORDER BY created_at').all(site.slug).map((r) => r.actor_uri); 178 const items = uris.map((u) => AP.buildActorRef(site.slug, u)); // name + avatar (shaer-aa3) 189 // Default = bare references; enrich only when the client asks (FEP-9876). 190 const items = wantsEnriched(req, res) ? uris.map((u) => AP.buildActorRef(site.slug, u)) : uris; 179 191 return AP.sendAP(res, AP.buildFollowers(baseUrl(req), site, items.length, items)); 180 192 } … … 190 202 if (!site) return res.status(404).end(); 191 203 if (owner) { 204 const enrich = wantsEnriched(req, res); // FEP-9876 opt-in 192 205 let items = []; 193 try { items = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => AP.buildActorRef(site.slug, r.actor_uri)); } catch { /* table may not exist */ } 206 try { 207 const uris = db.prepare("SELECT actor_uri FROM ap_following WHERE slug = ? AND status = 'accepted' ORDER BY created_at").all(site.slug).map((r) => r.actor_uri); 208 items = enrich ? uris.map((u) => AP.buildActorRef(site.slug, u)) : uris; 209 } catch { /* table may not exist */ } 194 210 return AP.sendAP(res, AP.buildFollowing(baseUrl(req), site, items.length, items)); 195 211 } -
src/services/ActivityPubService.js
r5143ccf r30871c1 667 667 } catch { /* ignore */ } 668 668 return { name: null, handle: deriveHandle(uri), icon: null }; 669 } 670 671 // FEP-9876: does this `Prefer` header ask for enriched (embedded) members? 672 // Pure and testable; the route sets the response headers around it. 673 export function prefersEnriched(preferHeader) { 674 return /(^|[,;\s])return=representation($|[,;\s])/i.test(String(preferHeader || '')); 669 675 } 670 676 … … 3070 3076 linkifyBody, bakePostContent, bakePostContentWithMentions, listFollowers, removeFollower, listConnections, 3071 3077 noteVisibility, isRejectedObject, rejectInteraction, interactionReportTarget, 3072 getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef, 3078 getMessages, notificationsSeenAt, ingestOutboxActivity, c2sVisibility, actorDisplay, buildActorRef, prefersEnriched, 3073 3079 }; -
test/c2s-contacts.test.js
r5143ccf r30871c1 44 44 assert.equal(ref.name, 'Dana'); 45 45 }); 46 47 test('prefersEnriched detects the Prefer opt-in (FEP-9876)', () => { 48 assert.equal(AP.prefersEnriched('return=representation'), true); 49 assert.equal(AP.prefersEnriched('return=representation; handling=lenient'), true); 50 assert.equal(AP.prefersEnriched('foo, return=representation'), true); 51 assert.equal(AP.prefersEnriched('return=minimal'), false); 52 assert.equal(AP.prefersEnriched('returnx=representation'), false); 53 assert.equal(AP.prefersEnriched(''), false); 54 assert.equal(AP.prefersEnriched(undefined), false); 55 });
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)