OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface commits / 74dc0f9

0.0.67: a bsky notification links to the actor's bsky.app profile (I2)
Test-first; 248/248. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74dc0f910e7996ad5433afbe93944df8f2a93d54
by plankatron <fleeky@gmail.com> · 2026-10-14T23:37:29.000Z

Changed files (3) +17 -2

lib/pages.js +9 -1
……@@ -981,6 +981,14 @@ function outsideActor (uri) {
981981 return '<a class="who" href="' + esc(url.href) + '" rel="nofollow noopener" target="_blank">' + esc(label) + '</a> <span class="who">(fediverse)</span>'
982982}
983983
984// A bsky actor is a DID (hyper-social #82, I2). Linked to its bsky.app profile — only a well-formed did: becomes a link.
985function bskyActor (did) {
986 const d = String(did || '')
987 if (!/^did:[a-z]+:[A-Za-z0-9._:%-]+$/.test(d)) return '<span class="who">' + esc(d || 'someone') + '</span> <span class="who">(bluesky)</span>'
988 const short = d.length > 24 ? d.slice(0, 20) + '…' : d
989 return '<a class="who" href="https://bsky.app/profile/' + esc(d) + '" rel="nofollow noopener" target="_blank">' + esc(short) + '</a> <span class="who">(bluesky)</span>'
990}
991
984992export function notifications (rows, profiles = null) {
985993 const VERB = {
986994 reaction: (n) => (n.value === 'like' ? 'liked' : 'reacted ' + esc(n.value || '')) + ' your post',
……@@ -997,7 +1005,7 @@ export function notifications (rows, profiles = null) {
9971005 ? ' <a href="/t/' + encodeURIComponent(n.target.feed + '/' + n.target.collection + '/' + n.target.name) + '">→</a>'
9981006 : ''
9991007 const snippet = n.body ? '<div class="who bio">' + esc(n.body.replace(/\s+/g, ' ').trim().slice(0, 120)) + '</div>' : ''
1000 const by = n.source === 'fediverse' ? outsideActor(n.author) : who(n.author, profiles)
1008 const by = n.source === 'fediverse' ? outsideActor(n.author) : n.source === 'bsky' ? bskyActor(n.author) : who(n.author, profiles)
10011009 return '<li>' + by + ' ' + verb + link + snippet + '</li>'
10021010 }).join('') + '</ul>'
10031011 : empty('No notifications.',
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-surface",
3 "version": "0.0.66",
3 "version": "0.0.67",
44 "description": "The favela renderer \u2014 server-side HTML over the daemon's socket. No storage, no keys, no swarm.",
55 "type": "module",
66 "main": "index.js",
test/pages.test.js +7 -0
……@@ -908,3 +908,10 @@ test('⛔ a fediverse author that is not an http(s) URL is never made a link', (
908908 const html = notifications([{ kind: 'follow', source: 'fediverse', author: 'javascript:alert(1)', at: '', target: null, name: 'x', body: '' }])
909909 t.absent(/href="javascript/i.test(html))
910910})
911
912test('★ a bsky notification links to the actor\'s bsky profile and says bluesky', (t) => {
913 const html = notifications([{ kind: 'reaction', value: 'like', source: 'bsky', author: 'did:plc:alicealicealice', at: '', target: null, name: 'b1', body: '' }])
914 t.ok(/href="https:\/\/bsky\.app\/profile\/did:plc:alicealicealice"/.test(html), 'links to the bsky profile')
915 t.ok(/bluesky/.test(html), 'and says where it came from')
916 t.absent(/\/u\/did:/.test(html), 'never as a favela profile path')
917})