Skip to content

feat: v3.0.0-dev — WHATWG SSE parser, interceptors, reconnect & more#46

Open
Imgkl wants to merge 34 commits into
mainfrom
pre-release
Open

feat: v3.0.0-dev — WHATWG SSE parser, interceptors, reconnect & more#46
Imgkl wants to merge 34 commits into
mainfrom
pre-release

Conversation

@Imgkl

@Imgkl Imgkl commented Mar 18, 2026

Copy link
Copy Markdown
Owner

Summary

Major release bringing EventFlux to full WHATWG SSE spec compliance with a modernized internal architecture.

Breaking

  • onReconnect callback signature changed from () to (int attempt, Duration delay)
  • Default request headers now include Cache-Control: no-store
  • Minimum Dart SDK raised to >=3.4.0, Flutter >=3.0.0
  • webConfig is now required when running on web

Added

  • WHATWG SSE spec-compliant parser (SseParser) — persistent lastEventId, retry: field support, trailing newline stripping, NULL character check, U+2028 sanitization
  • Request/response/error interceptor chain via EventFluxInterceptor — modify requests, inspect responses, suppress or transform errors
  • Mid-flight abort support via abortTrigger parameter
  • Idle timeout detection via connectionTimeout on ReconnectConfig
  • maxBackoff duration cap for exponential backoff
  • EventFluxStatus.reconnecting status value
  • originalError and stackTrace fields on EventFluxException
  • Event filtering via EventFluxResponse.where(eventType)
  • Smart error classification — only 5xx, 408, and 429 trigger auto-reconnect
  • macOS platform support for the example app

Fixed

  • Race conditions and safety issues resolved in code audit
  • Web support bugs in reconnection call sites (webConfig now passed correctly)
  • Exponential reconnect interval calculation

Architecture

Extracted internal modules into lib/src/:

  • SseParser — WHATWG-compliant SSE line parser
  • ReconnectStrategy — backoff management with jitter, maxBackoff cap, server retry: override
  • ConnectionConfig — immutable parameter bundle with copyWithHeader() for reconnect
  • RequestBuilder — stateless factory for Request/MultipartRequest/Abortable variants
  • InterceptorRunner — stateless executor for interceptor chains

Test plan

  • flutter test — all 200 tests pass (unit + integration)
  • flutter test test/integration/eventflux_test_vm.dart — 11 integration tests pass
  • flutter analyze — no issues found
  • CI: test-clients job runs integration tests (VM + browser)

🤖 Generated with Claude Code

Imgkl and others added 22 commits December 11, 2024 14:00
* fix: Interval calculation for exponential reconnect

* test: Add tests for multipart requests

* ref: Remove unnecessary async keyword

* test: Add tests for headers

* test: Add tests for correctly passing Url

* test: Add tests for get and post method
* fix: Interval calculation for exponential reconnect

* test: Add tests for multipart requests

* ref: Remove unnecessary async keyword

* test: Add tests for headers

* test: Add tests for correctly passing Url

* test: Add tests for get and post method
* 2.2.2-dev.2

* fix: Interval calculation for exponential reconnect

* test: Add tests for multipart requests

* ref: Remove unnecessary async keyword

* test: Add tests for headers

* test: Add tests for correctly passing Url

* test: Add tests for get and post method

* feat: Add browser support

* feat: Add Browser support

---------

Co-authored-by: Sai Gokula Krishnan <saigklkrishnan@gmail.com>
- Pass webConfig through _attemptReconnectIfNeeded to prevent null
  dereference crash on web during reconnection
- Export WebConfig and related enums from barrel file so users can
  import them via package:eventflux/eventflux.dart
- Add web to pubspec platforms section
- Replace debug-only assert with runtime ArgumentError for missing
  WebConfig on web
- Set correct error status on non-2xx responses instead of connected
- Sync EventFluxBase abstract class with concrete connect() signature

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The onDone, onError, and catchError handlers were not passing
webConfig to _attemptReconnectIfNeeded, causing a null dereference
crash on web during reconnection.

Closes #5

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge branch 'feat/preserve-original-error-and-stacktrace' into pre-release

Adds originalError and stackTrace fields to EventFluxException,
preserving the original error context at both error-wrapping sites
in client.dart. Resolves #44.

Co-Authored-By: krolmic <krolmic@users.noreply.github.com>
Recreates the 3 tests from PR #45 that were lost during merge when
test/eventflux_test.dart was removed. Covers construction with all
fields, catch-block preservation, and backward-compatible optionality.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix reconnect race condition by reading _isExplicitDisconnect field
  directly instead of stale parameter capture
- Set _status to connected on successful 200 response
- Reject non-200 2xx responses (only 200 is valid per SSE spec)
- Prevent onConnectionClose from firing twice via null-after-call guard
- Reset exponential backoff interval/maxAttempts after successful reconnect
- Replace non-null assertion on regex match with null check
- Add bounds/format validation to EventFluxData.fromData()
- Move RegExp to static final class-level field
- Fix exponential backoff log to show current interval, not next
- Add EventFluxException.toString() override
- Set CI min_coverage to 70, update Flutter SDK minimum to >=3.0.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y, abort support

Rewrite core into extracted, testable modules:
- SseParser: WHATWG-compliant SSE line parser with persistent lastEventId,
  retry: field forwarding, trailing \n strip, NULL/U+2028 handling
- ReconnectStrategy: linear/exponential backoff with 0-25% jitter,
  maxBackoff cap, server retry: override, attempt tracking
- ConnectionConfig: immutable connect() parameter bundle with
  copyWithHeader() for reconnect Last-Event-ID injection
- RequestBuilder: stateless factory for Request/MultipartRequest and
  their Abortable variants (http ^1.6.0)
- InterceptorRunner: stateless onRequest → onResponse → onError chain
  executor with error suppression (return null from onError)
- EventFluxInterceptor: abstract class for interceptor hooks

Additional changes:
- Error classification: only 5xx/408/429 trigger auto-reconnect
- Content-type validation on 200 responses
- Idle timeout (connectionTimeout) with timer reset on each line
- EventFluxStatus.reconnecting status during retry attempts
- where(eventType) on EventFluxResponse for stream filtering
- EventFluxData.json getter and fromData format validation
- AbortableRequest/AbortableMultipartRequest via abortTrigger param
- Connect guard rejects calls during reconnecting state
- Updated example app, CHANGELOG, README, and CLAUDE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Integration tests exercising multiple subsystems together:
- Connect → parse → deliver flow (GET and POST with body)
- Reconnection flow (500 retry, Last-Event-ID injection, 403 no-retry)
- Interceptor integration (auth headers, error suppression with reconnect)
- Disconnect flow (explicit disconnect, cancel during reconnect delay)
- Event filtering via where()
- Idle timeout triggering reconnect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Imgkl Imgkl changed the title v3.0.0-dev: WHATWG SSE parser, interceptors, reconnect strategy, abort support feat: v3.0.0-dev — WHATWG SSE parser, interceptors, reconnect & more Mar 18, 2026
Imgkl and others added 7 commits March 18, 2026 16:45
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enhanced the migration section for clarity with a collapsible details view.
- Improved SSE parsing performance comparison table formatting for better readability.
- Acknowledged contributors to the project in a more prominent manner.
- Increment version from v3.0.0-dev to v3.0.1-dev.
- Document breaking changes including updated `onReconnect` callback signature and new default request headers.
- Updated the eventflux dependency version from ^3.0.0-dev to ^3.0.1-dev.
- Confirmed Dart SDK and Flutter version requirements remain unchanged.
- Changed version from 3.0.1-dev to 3.0.0-dev in CHANGELOG.md, pubspec.yaml, and README.md.
- Updated breaking changes in the changelog to reflect the new versioning.
Imgkl and others added 5 commits March 18, 2026 19:34
- Changed version from 3.0.0-dev to 3.0.2-dev in CHANGELOG.md, pubspec.yaml, and README.md.
- Updated breaking changes in the changelog to reflect the new versioning.
…Error

The implementation throws ArgumentError when webConfig is missing on web,
but the test was expecting AssertionError, causing CI failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
very_good_workflows bundles tests when test_optimization is enabled,
which strips @teston annotations and runs browser tests on VM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pre-release branches always go through a PR to main, so the push
trigger just duplicates work and gets cancelled by concurrency.

Co-Authored-By: Claude Opus 4.6 (1M context) <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.

4 participants