The logic in the fetch spec behind whether a browser request needs a preflight is based on whether it is "simple". For example, setting custom headers is not simple and requires a preflight. My understanding is that this is mostly about ensuring that the request is likely to be "getting a resource" and not "executing an API".
One of the conditions is that the body is not a ReadableStream. Why does that matter? From a security perspective, I can imagine "anything with a body at all should be preflighted" making sense, but that's not the logic: it's "strings are OK, ReadableStreams are not".