SIGN IN SIGN UP

refactor(core): ask serde for a map, instead of reading the first byte

I was wrong about this one and Indy was right to push.

The object gate scanned for the first non-whitespace byte and required
`{`. I defended that by saying the pure-serde alternatives parse twice —
which is true of the two I had actually evaluated (round-tripping
through `Value` or `Map`, both of which build a whole intermediate tree)
and false as a statement about serde. Serde has a single-pass answer and
I did not go looking for it.

The derive asks the deserializer for a STRUCT, and `serde_json` answers
that request by accepting either `{` or `[`. `ObjectOnly` sits between
the two and forwards that one request as a request for a MAP, which
`serde_json` answers with `{` alone:

    derive              adapter              serde_json      input
    deserialize_struct → deserialize_map  →  expects `{`  ←  {"a":1}  ok
                                                          ←  [1]      refused

One pass, no intermediate, nothing scanning bytes. Everything else
forwards untouched, so a missing field, a wrong type and a borrowed
`&'de str` behave exactly as they do without the adapter, and only the
TOP level is constrained — the same scope `loadJson`'s
`parsed.value != .object` has.

It is also a better refusal than the one it replaces. The byte scan
answered a generic "expected a JSON object" this module had to word
itself; serde answers `invalid type: sequence, expected struct Pair`,
naming the type that was wanted. Two of the tests now assert on serde's
message rather than on a string of ours.

Separately, `ssrf`'s test helpers were re-parsing whole URLs to reach a
host — duplicating the parse `endpoint` already owns, so every range
assertion was re-exercising a parser that is not this module's subject.
They build a `Host` directly now. The two meet where a URL is actually
the point, in `endpoint`'s own SSRF-range test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
K
Kishore Kumar committed
3288bfb92fdcc53b919b7af7eed5d0c4463720cf
Parent: 3fa990e