///|
/// JRD parsing entry points.
///
/// `parse_jrd` parses a JSON document into the JRD model under default
/// limits; `parse_jrd_with_limits` lets callers tighten or relax every
/// bound. Both convert every failure — empty input, oversized input,
/// JSON syntax errors, a non-object root, wrong member types, missing
/// required link members, or limit violations — into a structured
/// `WebFingerError`. Neither can panic on any input.
///
/// RFC 7033 Section 4.4 requires that clients MUST ignore unknown JRD
/// members, so unknown members are preserved as extensions rather than
/// rejected. Known members with the wrong JSON type are rejected: the
/// RFC defines their shapes normatively and gives no licence to accept
/// other shapes silently.

///|
/// Parse a JRD document under `Limits::default()`.
pub fn parse_jrd(
  input : String,
) -> Result[JsonResourceDescriptor, WebFingerError] {
  parse_jrd_with_limits(input, Limits::default())
}

///|
/// Parse a JRD document under caller-supplied limits.
pub fn parse_jrd_with_limits(
  input : String,
  limits : Limits,
) -> Result[JsonResourceDescriptor, WebFingerError] {
  try {
    if input.length() == 0 {
      raise WebFingerError(Input, EmptyInput, None, "input is empty")
    }
    let byte_len = utf8_byte_length(input)
    if byte_len > limits.max_input_bytes {
      raise WebFingerError(
        Limit,
        LimitExceeded,
        None,
        "input is \{byte_len} bytes; limit is \{limits.max_input_bytes}",
      )
    }
    let j = @json.parse(input) catch {
      e =>
        raise WebFingerError(
          Json,
          InvalidJson,
          None,
          "JSON syntax error: \{e.to_string()}",
        )
    }
    Ok(json_to_jrd_inner(j, limits, 1))
  } catch {
    e => Err(unwrap_webfinger_error(e))
  }
}