Static ReadonlyCOMPOSER_The single User Setting key holding all drafts.
Static ReadonlyMAX_Per-draft length cap (chars of serialized text).
Static ReadonlyMAX_Most drafts retained; least-recently-updated evicted beyond this.
Static ReadonlyNEW_Map key for the new-conversation (not-yet-created) composer.
Deletes a conversation's draft (message sent / draft abandoned) and persists immediately.
Persists the current map immediately (blur / conversation switch / teardown).
The stored draft for a conversation (or the new-convo composer), if any.
Records the current draft (debounced persistence). Empty text clears the entry instead — the map never holds blank drafts.
StaticKeyNormalizes a conversation id (null = the new-conversation composer) to its map key.
Per-user persistence for in-progress (un-sent) composer drafts, so a message the user was writing survives conversation switches, page refreshes, and devices.
Storage: ONE
MJ: User Settingsrow via UserInfoEngine (never localStorage — see the root CLAUDE.md persistence rule), key COMPOSER_DRAFTS_SETTING, value = a JSON map of'new' | <conversationId-lowercased>→ the SERIALIZED draft (the composer'sgetPlainTextWithJsonMentions()format, so mention pills round-trip losslessly through the editor's rehydratingwriteValue).Contracts:
SetSettingDebounced); Flush persists immediately (blur / conversation switch).