Adapters and Fluxer compatibility
Adapters connect generic runtime services to Fluxer’s interface. Keep this boundary separate from both installation compatibility checks and plugin-specific feature logic.
Adapter responsibilities
Section titled “Adapter responsibilities”FluxerAdapter identifies supported documents and supplies client-info injection, composer attachment actions, the settings surface, and optional posted-file context actions, user badges, decorations, right-click menu items, message box input and the voice state.
Core supplies generic callbacks and data. Adapters handle the DOM structure needed to attach those features and return cleanup functions.
Changes to Fluxer markup
Section titled “Changes to Fluxer markup”When upstream structure changes, reproduce the relevant surface with a controlled DOM fixture. Verify action placement, submenu ownership, focus behavior, rerender survival, and cleanup.
Avoid broad selectors that capture unrelated controls. Ensure a missing surface fails gracefully without repeatedly creating orphaned nodes.
A structurally compatible app archive can still have changed UI markup. Installation detection and DOM adaptation need separate evidence.
Plugin selectors
Section titled “Plugin selectors”Neko sprite selectors and inspection presentation belong in their plugin. Adding a new plugin selector is not a reason to create a feature-specific runtime API.
Named hooks expose serialized values rather than arbitrary function replacement: client-info.lines and badges.merge, each with its own check on what handlers return.
slot-engine.ts keeps FluxPlugs-owned elements in place on Fluxer’s pages. A spec names the elements a surface is built around, reads what each one reveals, and says where its slot goes; the engine creates, fills, re-places and removes slots as React re-renders, throttled and within a per-pass budget. Every slot carries data-fluxplugs-slot, so one engine’s changes never trigger another, and slots sharing a place are ordered by the spec’s order (badges before decorations). Badges and decorations are both built on it.
Decorations, menus and the message box
Section titled “Decorations, menus and the message box”observeDecorations finds messages (the article element, which carries message, channel, guild and author ids plus flags) and member-list rows, and asks a DecorationSource what to draw below the content, next to the author and next to member names. It reads ids and flags only, never names; message text comes from Fluxer’s copy text and is read only when the source asks.
registerContextMenuAction records what a right-click landed on (a person, a channel item or a message) and adds items to the menu that opens right after; an item’s only filter compares the target’s self flag. observeComposer tracks the message box and types text in with editing commands, falling back to a paste event, and never sends.
Settings surface and voice
Section titled “Settings surface and voice”registerSettingsSurface adds FluxPlugs’ category to Fluxer’s settings sidebar. Its setPages lists plugins’ pages after Plugins and Settings; render receives a slot (the content area, whether it is on screen and uncovered, the settings window’s stacking level) and onHide hears when a shown page is left.
readVoiceState and observeVoiceState read the voice connection panel above the user area. The channel and community come from the panel’s jump-to-channel link. Fluxer marks the connection state only with CSS-module classes, so the adapter matches their local names (such as __statusConnected___) and falls back to the signal icon, which is drawn only while connected. The pending message flag uses the same kind of class match, backed by the failed-message footer’s data-flx. These are exceptions to data-flx selectors, so keep a fallback beside each and cover both in unit tests. When the user area isn’t on screen, the adapter answers undefined and the runtime keeps the last state.
User badges
Section titled “User badges”observeUserBadges is the adapter’s generic badge surface. It finds user names and role entries on Fluxer’s pages (message headers, member-list rows and group headers, profiles, the role settings list and reply previews), reads what each one reveals (user id, role id, name colour, profile role pills, owner mark), and asks a BadgeSource what to draw. Badge containers are the only nodes it adds; every pass re-places them after React re-renders and removes unwanted ones. Nothing in it knows which plugin supplied a badge or why.
Run adapter tests and pnpm test:architecture for integration changes; use Electron fixtures when the change affects full runtime startup or menu behavior.
