SyniRuntimeResponse.fromJson constructor

SyniRuntimeResponse.fromJson(
  1. String json
)

Parse a runtime response string.

  • A success is the bare payload ({"type":…,"data":…}), optionally with a sibling meta object when a fallback was substituted.
  • A failure is the runtime's {"ok":false,"error":{…}} envelope — rethrown as a typed SyniRuntimeError carrying code/retryable, so a failure never masquerades as a valid (but fieldless) response.
  • Malformed native output (non-JSON, non-object) becomes a typed SyniRuntimeError.protocol rather than a leaked FormatException or a silent unknown success.

Implementation

factory SyniRuntimeResponse.fromJson(String json) {
  final dynamic decoded;
  try {
    decoded = jsonDecode(json);
  } on FormatException catch (e) {
    throw SyniRuntimeError.protocol(
        'runtime returned malformed JSON: ${e.message}');
  }

  if (decoded is! Map) {
    throw SyniRuntimeError.protocol(
      'runtime returned a non-object response (${decoded.runtimeType})',
    );
  }

  // Failure envelope: `ok` explicitly false. A missing/other `ok` is a
  // success payload (the backward-compatible bare-payload contract).
  if (decoded['ok'] == false) {
    final error = decoded['error'];
    throw SyniRuntimeError.fromEnvelope(
      error is Map
          ? error.cast<String, dynamic>()
          : const <String, dynamic>{},
    );
  }

  // Optional fallback metadata — present only when the runtime substituted a
  // fallback. Absent ⇒ genuine answer (or an older runtime).
  var isFallback = false;
  String? fallbackReason;
  String? underlyingErrorCode;
  var retryable = false;
  final meta = decoded['meta'];
  if (meta is Map && meta['fallback_used'] == true) {
    isFallback = true;
    fallbackReason = _asString(meta['fallback_reason']);
    underlyingErrorCode = _asString(meta['error_code']);
    retryable = meta['retryable'] == true;
  }

  return SyniRuntimeResponse._(
    json,
    decoded,
    isFallback: isFallback,
    fallbackReason: fallbackReason,
    underlyingErrorCode: underlyingErrorCode,
    retryable: retryable,
  );
}