@estiva-app/conversation
v0.22.0
Published
The conversation rules of the Estiva SPEC (§6.2–§6.8, §11): comment and mention strengths, threading, the edit, reaction and attachment folds, NIP-22 comment and reply builders, drafts, NIP-RS read state, membership and unread. A convenience an app adopts
Maintainers
Readme
@estiva-app/conversation
The conversation rules of the Estiva SPEC §6.2–§6.8, for an app that would rather not implement them itself. Peek, Ship and estiva-agent read conversations through it.
A convenience, never a requirement. SPEC §9's conversation checks
(C10–C18) are written so an app can build conversations from the specification
alone, and this package's tests are those checks
(test/conformance.test.ts for C10–C16, test/membership.test.ts for C17 and C18, test/textMentions.test.ts for C28). If you find this package disagreeing with the
SPEC, the package is wrong.
npm install @estiva-app/conversation @estiva-app/protocol@estiva-app/protocol is a peer. Nothing here opens a socket, holds a
credential or touches a browser global: the relay read is a QueryFn you
pass, the clock is a createdAtMs you pass, and drafts take their storage.
What is in it
| | SPEC | exports |
| --- | --- | --- |
| comment or mention | §6.4 | isCommentOn, strengthOn, threadStrength, anchorsOf, isReply, namedInBody |
| threading | §6.4 Replies | parentOf, groupThreads |
| writing | §6.4, §13.6 | buildComment, buildReply, placeOf, referenceTagsFor, mentionTagsFor |
| what a composer's pick writes | §13.1 | mentionText, messageReference, urgentTagsFor, URGENT_TAG |
| what the shared comment box holds, as the message it writes, and back | §13.1 | composerText, composerDocument, withoutNewUrgency, composerDraft |
| what a box shows under itself while a comment is written: the one file's card and each block link's part, and the embed a send or an edit writes | §13.6.1, §13.6.2 | boxReadOf, boxLinksOf, embedsToSend, embedsToEdit, namedBefore, withoutCard, linkTargetOf |
| what [ offers, and in what order | §13.1 | rankReferences, referenceMatch, fileReference, referenceSearch, MESSAGE_TIER, FILE_TIER, REFERENCE_CAPS |
| ordering | §6.2, §6.3 | trustedTs, orderingMs, byOrder |
| edits and attachments | §6.8 | editTargetOf, foldEdits, foldAttachments |
| reactions | §6.6 | REACTION_HORIZON, reactionHorizon, reactionTargetOf, reactionEmojiOf, foldReactions |
| one read for all of the above | §6.6, §6.8 | decorationsOf |
| which controls to offer | §6.5 | offersEditAndDelete |
| drafts | — | createDraftStore, draftKeys |
| membership | §11.8 | membershipOf, membersOf, streamOf, membershipFilters, candidateFilesOf, buildMembershipChange |
| muting | §11.8 | parseMutedBlob, serializeMutedBlob, buildMutedEvent, mutedFilter, mutedFromFollowed |
| read state | §11.1–§11.6 | channelContext, fileContext, threadContext, loadSlotIdentity, advanceContexts, fetchReadState, publishReadState, mergeSlots, effectiveReadAt, THREAD_RULE_FROM, REPLY_FLOOR_CONTEXT, capReadStateContexts |
| unread | §11.3, §11.8 | unreadIn, isUnread |
| a mention in a file's text | §11.8, §13.1 | mentionAddsFor, newlyNamedPeople, peopleNamedInText |
Chat, an edit, a reaction and a deletion are built with
@estiva-app/protocol's buildMessage, buildEdit, buildReaction and
buildDeletion.
Read state takes its environment like the rest: slot storage and randomness
(loadSlotIdentity), the relay query, the signer and NIP-44 (fetchReadState,
publishReadState). When to write — the debounce, the dwell before a view
counts as read — stays the app's.
Light a dot from the files you already load, not from discovery alone. A
file's membership comes from membershipOf over that file's own events, which
an app already holds for any file it shows. membershipFilters is for listing
"your files", and a busy person's results are cut short by the relay's limit
(each filter returned 2,000 events for one person in 90 days on 2026-10-01). A
dot built only on discovery would miss a file the limit dropped.
What is not in it
The views (CON-18), the composer's editor and its @, !@, [ and /
menus (@estiva-app/ui/editor, which writes through mentionText and
messageReference above), a Folder's roster (the relay's
kind:39002), and anything only one app needs.
