Changeset fa33214 in Klonkt for src/routes
- Timestamp:
- 08/04/2026 12:55:55 PM (5 weeks ago)
- Branches:
- main
- Children:
- 04aca12, 12bed59
- Parents:
- 3d882bd
- Location:
- src/routes
- Files:
-
- 2 edited
-
activitypub.js (modified) (2 diffs)
-
guardian.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/activitypub.js
r3d882bd rfa33214 254 254 queueRoute('offers', (id, slug, me) => Guardianship.offersCollection(id, slug, me)); 255 255 queueRoute('follows', (id) => Guardianship.followsCollection(id)); 256 // §5.3 turned around (shaer-p729): what this ward has asked to follow, still 257 // waiting on its guardians. Owner-only like the rest — who a child wants to 258 // follow is nobody else's business. 259 queueRoute('outgoing-follows', (id, slug, me) => Guardianship.outgoingFollowsCollection(id, slug, me)); 256 260 queueRoute('wards', (id, slug) => Guardianship.wardsCollection(id, slug)); 257 261 // Availability (FEP-633c 3.6.1) is never public: the ward reads its … … 696 700 // 201 Created → Location header (AP spec); 202 Accepted for side-effect verbs. 697 701 if (out.status === 201 && out.url) res.set('Location', out.url); 698 return res.status(out.status || 202).json({ ok: true, id: out.id, url: out.url }); 702 // `state` carries a third outcome the app must be able to tell apart from a 703 // plain success: a ward's follow held for its guardians (§5.3, shaer-p729). 704 return res.status(out.status || 202).json({ ok: true, id: out.id, url: out.url, ...(out.state ? { state: out.state } : {}) }); 699 705 }); 700 706 -
src/routes/guardian.js
r3d882bd rfa33214 278 278 }); 279 279 280 // ── §5.3, the other direction (shaer-p729): the ward wants to follow SOMEONE, 281 // and the guardians decide. Same quorum arithmetic and the same availability 282 // rules as the inbound gate above; only the question is turned around, which 283 // is why it gets its own endpoint rather than a flag on that one. 284 router.post('/api/outgoing-follow/:id', requireAuth, express.json({ limit: '4kb' }), async (req, res) => { 285 const site = siteForUser(req); 286 if (!site) return res.status(404).json({ error: 'no_site' }); 287 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 288 const me = AP.actorId(base, site.slug); 289 const decision = req.body?.decision === 'reject' ? 'reject' : 'approve'; 290 291 const pending = Guardianship.outgoing.getPending(req.params.id); 292 if (!pending) return res.status(404).json({ error: 'gone' }); 293 const allGuardians = Guardianship.listGuardians(pending.ward_slug).map((g) => g.other_uri); 294 if (!allGuardians.includes(me)) return res.status(403).json({ error: 'not_a_guardian' }); 295 Guardianship.availability.oneAnswer(me, Date.now()); 296 const guardians = Guardianship.availability.availableSet(pending.ward_slug, allGuardians, Date.now()); 297 const r = Guardianship.outgoing.decide(pending.id, me, decision, guardians); 298 try { 299 // Only on approval does anything leave the building. A refusal is a local 300 // fact: the follow was never sent, so there is nothing out there to undo 301 // and nobody to inform that a child asked about them. 302 if (r.outcome === 'approved') await AP.performApprovedFollow(r.follow); 303 } catch { return res.status(502).json({ error: 'delivery', outcome: r.outcome }); } 304 res.json({ ok: true, outcome: r.outcome }); 305 }); 306 280 307 // ── Wave (FEP-633c §5, shaer:wave): a gentle "thinking of you" from a 281 308 // guardian to a ward. A private direct note, never a feed post. Warmth
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)