Repository navigation
Face room invites: previewInvite has three layers and no client, so a join never shows the room first #798
Description
What already exists on main (fd205c40)
Three layers of the invite preview are written and tested, and no fourth layer uses them:
plugins/social/src/face-rooms.js:680—previewInvite(ticket);GET /invites/<ticket>, and at:686-693it returns{roomId, name, lead, members, maxMembers, expiresAt}.plugins/social/src/social.js:369—SOCIAL_UI_ENDPOINTS;:376already lists'social/face-invite-preview'next toface-inviteandface-invite-revoke;:386registers every name in that array;:3529binds the handler and gates it onserverInvites(), so an older Bot Social answers{unsupported: true}instead of being called.plugins/social/test/social.test.jscovers the api method.
What is missing
The client. plugins/social/client.js calls social/face-join-invite (:1247, in joinLink), social/face-invite and social/face-invite-revoke; it never calls the preview. So today a person who pastes an invite link or scans one joins a room they have not seen: no name, no lead, no member count, no expiry. The three layers above are unreachable from the UI, which is why this issue exists rather than a silent deletion.
The follow-up
In the join dialog, after a link is pasted or a code is scanned and before any Bot joins, show the room: name, lead, members (members/maxMembers when both are numbers), and expiry when the server sends one, with the same two ways out the dialog already has (join, or clear the field).
Two things the wiring must get right
nameis the server's raw string.face-rooms.js:688returnsString(body.name)as-is while:689runsleadthroughcleanFaceName. A remote room controls that string; rendering it before the same cleaning gives a stranger's text a place in our dialog. Either cleannameinpreviewInvitethe wayleadis cleaned, or clean at render time — but not "somewhere later".- The preview must not block a join that could work. A
404or a timeout falls through to the join that works today.{unsupported: true}is the exception: the preview andface-join-invitesit behind the sameface_room_invitesswitch, so on such a server the join fails with the same sentence anyway — showInvites need a newer Bot Social. The 6-digit number still works.and do not call join (owner decision, 2026-10-23).
Out of scope
- Changing
joinInvite, the ticket format, or the scan path. - Showing the preview for a 6-digit room number (that is a different route,
social/face-join).
Done when
- Pasting or scanning an invite in the join dialog shows room name, lead and member count before a Bot joins; the name is cleaned as above; a missing/older-server preview is skipped and the existing join path keeps its current sentence.
- Two tests: a preview fixture whose
namecontains markup renders cleaned text; a404/timeout fixture still joins and shows no error, and anunsupportedfixture shows the sentence and makes no join call.
Why it is not agent-ready yet
Chief scoped this out of #774 on purpose ("keep it, do not wire it into any screen this version"), and it changes what a person sees at the moment of joining. It becomes ready when the owner asks for the wiring.
Activity
Birfy commentedon Oct 23, 2026
Opened per Chief's decision on
#774: keeppreviewInvite, do not wire it into any screen this version, and record the wiring here so the three finished layers do not sit as unattributed dead code.Label:
enhancement | area:social | area:uiand no status label on purpose. Nothing is blocked on an answer — the answer is already "not this version". It becomesagent-readywhen the owner asks for the wiring; until then it is backlog, and marking itneeds-humanwould put it in the queue of things waiting for a word that has already been given.Checked while writing it, on
mainfd205c40:plugins/social/src/social.js:369SOCIAL_UI_ENDPOINTS,:376already listssocial/face-invite-preview,:386registers it,:3529binds the handler behindserverInvites();plugins/social/src/face-rooms.js:680is the api method and:686-693its answer.plugins/social/client.jsnever calls it — the only invite route it uses issocial/face-join-inviteat:1247. Two details worth fixing at wiring time are in the body:nameis returned raw at:688whileleadis cleaned at:689, and the preview must never be able to block a join.Birfy commentedon Oct 23, 2026
Triage:
agent-ready. The three backend layers are on6f9b60c7—previewInvite(plugins/social/src/face-rooms.js:680), the endpoint id inSOCIAL_UI_ENDPOINTS(social.js:390) and the handler with its{unsupported: true}fallback for older servers (social.js:3550). The client still has none of it:plugins/social/client.jscontains nopreviewInviteand noface-invite-preview, and the join goes straight from the parsed ticket to the server at:1247.The scan path is worse than the paste path and is worth naming:
beginScanhands a recognised link tovoid joinLink(raw)(:1271), so a scan can put a Bot in a room on the same click that decoded the code, with nothing shown in between.Acceptance
After
faceInviteTicket(text)succeeds — on the paste path (joinLink,:1232) and on the scan path (:1271) — and before any call tosocial/face-join-invite, callsocial/face-invite-previewwith the ticket and render a confirmation card. The join happens only on an explicit confirm.The card shows, in this order, and only what the server actually returned:
preview.nameis a plain string (face-rooms.js:690). It is rendered as text, never as markup: a room named<b>x</b>must show those characters. An empty string omits the title; it must not printundefined.undefined(:691-692), so the client must showN / Monly when both are finite numbers,Nalone when only one is, and nothing at all when neither is.undefined,NaN, or a fabricated0is a failure of this issue, not a cosmetic bug.:1240).{unsupported: true}from the preview (an older Bot Social,social.js:3550) showsINVITE_UNSUPPORTEDand stops without calling join — the same sentence the join path already produces at:1248, so nothing changes for old servers.Cancelling the card leaves no trace: no
social/face-join-invite, nosocial/face-leave, no session opened, no room state.Done when the client cases in
plugins/social/test/social.test.js(the file that already exercisessocial/face-join-inviteand loadsclient.js) cover: preview called once and join not called before confirm; join called once after confirm with the same ticket and the picked Bot; a name containing markup rendered literally;memberspresent withmaxMembersundefined → one number, no slash, noundefined; both undefined → the line is absent; expiredexpiresAt→ confirm disabled and no join;{unsupported: true}→INVITE_UNSUPPORTEDand no join; scan path → the same card, no automatic join.Kill conditions
previewInvite's return shape, or a change toface-rooms.js/social.jsbeyond what the client needs.namereaching the DOM as markup (innerHTML,dangerouslySetInnerHTML, or an attribute built by string concatenation).social/face-join-invitefires before the card is confirmed — including the scan path.undefined/NaNreaching the card, or0substituted for a count the server did not send.unsupported(a network error must not lock the user out of a room they can still enter).Out of scope
The backend preview, its normalisation, and the endpoint list; the mint/revoke UI; the QR and camera code (
startFaceScan); how a room is left after joining; the room card in the session header.Birfy commentedon Oct 23, 2026
Written-by: Dev2
Claiming this. Branch:
feat/798-invite-previewonBirfy/FlyBot, cut from forkmainat6f9b60c7; the pull request will reference this issue asFixes ThinkFlowLab/FlyBot#798.Scope as written: one
social/face-invite-previewcall insidejoinLinkand a confirmation card in the join dialog. No new endpoints, no change to the backend response shape,joinInvite/ticket format/scan path untouched.feat(social): show a room's invite before it is joined (ThinkFlowLab#798
feat(social): show a room's invite before it is joined (ThinkFlowLab#798
Birfy commentedon Oct 23, 2026
Acceptance amended after the merge (owner decision, 2026-10-23).
Original item 2: “The preview must never block the join. A server that answers
404/{unsupported: true}/ a timeout falls through to the join that works today.”Now:
404and timeouts still fall through to today's join.{unsupported: true}does not, becauseface-invite-previewandface-join-inviteare gated on the sameface_room_invitesswitch — the join would fail with the same sentence and only cost a round trip. It showsInvites need a newer Bot Social. The 6-digit number still works.and makes no join call. TheDone whenline was updated the same way.This matches what shipped in #35 (
plugin/social/client.jsmerged at3d062b9f:previewLinkreturns onunsupported, andjoinTicketkeeps its defensiveunsupportedbranch).