API
DaisyFilter exposes a small, stable public API for other plugins. The API is
registered through Bukkit’s ServicesManager.
DaisyFilterApi filter = Bukkit.getServicesManager() .load(DaisyFilterApi.class);
FilterResult result = filter.scanPlain(actorId, FilterSurface.CUSTOM, text);if (!result.isAllowed()) { // react to result.getDisposition(), result.getSeverity(), etc.}Surface
Section titled “Surface”interface DaisyFilterApi { FilterResult scan(FilterInput input); FilterResult scanPlain(UUID actorId, FilterSurface surface, String text); boolean isAllowed(UUID actorId, FilterSurface surface, String text); EngineStatus status();}scan is synchronous, thread-safe, and pure: it performs no logging, no
spam-state mutation, no punishment, and no Bukkit side effects. It is safe to call
from async chat threads. Inputs are bounded; custom API input is capped at 4,096
code points.
FilterInput, MessageContext, FilterSurface, NormalizedText,
FilterDisposition, FilterAction, RuleMatch, HeuristicMatch,
FilterResult, EngineStatus. Results are immutable and expose only safe
metadata (masked previews and rule IDs), never stored raw content.
Events
Section titled “Events”DaisyFilter does not currently fire Bukkit events. Earlier versions of this page listed
DaisyFilterViolationEvent, DaisyFilterActionEvent, and DaisyFilterReloadEvent; none of them were
ever implemented, and documenting them was a mistake.
To react to filtering today, call the registered service yourself — scan is pure and side-effect
free, so you can run it against your own text without touching DaisyFilter’s state or recording an
incident. If you need to observe DaisyFilter’s own decisions rather than make your own, open an issue
describing the use case; an event surface is worth designing around a real consumer rather than
guessing at one.
The engine never exposes mutable internals or global singleton state. Do not
retain FilterResult spans to reconstruct blocked terms — censoring is one-way.