Skip to content

Conversation

@grdsdev
Copy link
Contributor

@grdsdev grdsdev commented Jan 23, 2026

Summary

Improve JSON parsing resilience across all Supabase Flutter SDK packages with explicit type validation and robust error handling. Support both int and num numeric types to handle different JSON decoder behaviors. Add unknown enum values for forward compatibility.

Changes

  • Add explicit type casts (as String, as Map<String, dynamic>) for all JSON fields
  • Change numeric type checks from is! int to is! num with .toInt() conversion
  • Add comprehensive validation for required fields with clear FormatException messages
  • Add unknown enum values to FactorType and FactorStatus for forward compatibility
  • Fix input map mutation in Presence.fromJson and PostgresChangePayload.fromPayload

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling and validation across auth, session, MFA, realtime, storage, and PostgREST flows to avoid crashes on malformed or unexpected server responses.
    • More robust MFA handling to tolerate unknown factor types/statuses and provide clearer errors for invalid data.
  • Refactor

    • Safer deserialization and construction paths for sessions, presence, storage objects, change payloads, and token refresh disposal for more predictable behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Add explicit type casts and validation for JSON parsing across all SDK
packages. Support both int and num numeric types for better compatibility
with different JSON decoders. Add unknown enum values for forward
compatibility with new factor types and statuses.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Hardened JSON deserialization across multiple packages by replacing direct parsing/force-unwrapping with factories/private parsers, adding runtime type checks and casts, introducing unknown enum variants, validating numeric/date fields, and improving error messages via FormatException (no public API removals).

Changes

Cohort / File(s) Summary
Auth response parsing
packages/gotrue/lib/src/types/auth_response.dart
Replace force-unwrapped User.fromJson(json) with private _parseUser that validates and throws FormatException on failure.
Gotrue client dispose
packages/gotrue/lib/src/gotrue_client.dart
Guard token-refresh completer completion with null and isCompleted checks before completing with AuthException('Disposed').
MFA deserialization
packages/gotrue/lib/src/types/mfa.dart
Add FactorType.unknown and FactorStatus.unknown; explicit casts for ids/strings; numeric validation for expires fields; parseDateTime helper; stricter mapping/type checks across MFA responses.
Session parsing
packages/gotrue/lib/src/types/session.dart
Validate user is a Map<String, dynamic>, parse into local user via User.fromJson, and throw FormatException on invalid input.
Postgrest response validation
packages/postgrest/lib/src/types.dart
Validate count is numeric, convert with toInt(), and throw FormatException if invalid in PostgrestResponse.fromJson.
Realtime presence
packages/realtime_client/lib/src/realtime_presence.dart
Add const named constructor for Presence; convert Presence.fromJson to a factory extracting presence_ref, defaulting missing values, and avoiding input mutation.
Realtime types (change payload)
packages/realtime_client/lib/src/types.dart
Convert PostgresChangePayload.fromPayload to a factory; safe parsing for commit_timestamp (fallback epoch), enforce map types for new/old records, and add timestamp parsing error handling.
Storage client types
packages/storage_client/lib/src/types.dart
Convert Bucket.fromJson, FileObject.fromJson, and FileObjectV2.fromJson to factory constructors; add runtime type checks, normalize owner, validate allowed_mime_types, and throw FormatException on invalid inputs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I nibble lines and mend each field,
Guarding types so nothing yields.
Unknowns tucked in gentle rows,
Errors caught before they grow.
A rabbit's hop—safe JSON flows. 🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(types): improve JSON decoding resilience' accurately summarizes the main objective of the pull request, which focuses on improving JSON parsing robustness and resilience across multiple type files with better validation and error handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@grdsdev grdsdev requested a review from a team January 23, 2026 11:03
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/gotrue/lib/src/types/session.dart`:
- Around line 34-46: The FormatException constructors in the session parsing
(the userJson check and the User.fromJson null branch) currently include
json.toString(), which can leak tokens/PII; update these throws to omit the full
payload or supply a redacted summary instead (e.g., no second argument or a
small redacted map/string), altering the two places that construct
FormatException around userJson and User.fromJson to avoid embedding the
original json contents.
🧹 Nitpick comments (1)
packages/realtime_client/lib/src/realtime_presence.dart (1)

18-26: Good implementation that correctly avoids input mutation.

The shallow copy with Map<String, dynamic>.from(map) before removing 'presence_ref' properly addresses the mutation concern mentioned in the PR objectives. The null-coalescing to empty string provides sensible resilient decoding.

Minor note: In deepClone() (line 30-31), if payload somehow contains a 'presence_ref' key, it would shadow the explicit assignment due to spread order. This is unlikely given fromJson removes it, but you could swap the order for defensive coding:

return Presence.fromJson({
  ...payload,
  'presence_ref': presenceRef,  // Ensure this takes precedence
});

grdsdev and others added 2 commits January 23, 2026 08:28
Avoid leaking tokens and PII by removing json.toString() from
FormatException constructors in Session.fromJson.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Check if the completer is already completed before calling completeError
in dispose() to avoid "Bad state: Future already completed" errors during
concurrent dispose operations.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants