Skip to content

feat: realtime accessibility, SSE streaming, ring buffers, cache invalidation (#251 #252 #253 #254) - #424

Open
edwardmiracle916-wq wants to merge 1 commit into
Refract-Protocol:mainfrom
edwardmiracle916-wq:feat/251-252-253-254-realtime-accessibility
Open

edwardmiracle916-wq wants to merge 1 commit into
Refract-Protocol:mainfrom
edwardmiracle916-wq:feat/251-252-253-254-realtime-accessibility

Conversation

@edwardmiracle916-wq

Copy link
Copy Markdown

Summary

Implements four issues that make the realtime streaming transport actually useful and accessible to all users:

Closes #251 — Throttled ARIA live regions

  • AriaLiveProvider renders a visually-hidden region
  • 2-second throttle window (5s with ) so the screen reader isn't machine-gunned by high-frequency streams
  • Batch coalescing: multiple messages in the same synchronous tick are joined into a single announcement
  • useAriaLive() hook provides an function to any component
  • RealtimeSyncProvider calls for each incoming realtime event

Closes #252 — Horizon SSE streaming for tx history

  • streamOperations() in uses the browser-native API on Horizon's SSE endpoint ( with )
  • Reuses existing for Refract contract-ID filtering
  • useTransactionHistory now does an initial REST page load, then opens an SSE stream for live updates; new entries are prepended and de-duped by id
  • continues to use REST cursor pagination for older pages
  • Added boolean to the hook's state for UI feedback

Closes #253 — Bounded per-topic ring buffers

  • RingBuffer<T> class: fixed-capacity, push evicts oldest, , (shallow copy), , , ,
  • RealtimeClient now buffers each topic's events in a with documented caps from (oracle: 100, claims: 50, pool: 50, policy: 50, default: 50)
  • topics.ts module: , , ,
  • Exposed and on the client

Closes #254 — Wire realtime events into shared cache

  • RealtimeSyncProvider subscribes to all realtime topics and calls with the mapping (prefix-based)
  • Also announces each event via so screen-reader users learn about changes
  • providers.tsx wiring:

What was tested

  • 33 new unit tests — all passing:
    • — 12 tests (capacity, eviction, latest, toArray copy, clear, edge cases)
    • — 6 tests (renders region, flush, coalescing, throttle window, empty messages, no-op outside provider)
    • — 8 tests (parseOperations filtering, streamOperations onEntry/onError/malformed/unavailable)
    • — 7 tests (mount/unmount, children render, query invalidation, TOPIC_TO_QUERY_KEYS mapping)
  • Typecheck: 0 new errors (12 pre-existing in )
  • Full test suite: 179 passed, 46 failed (all pre-existing)
  • Build: fails on pre-existing syntax error (unchanged)

Infrastructure fixes

  • Updated to include test files, jsdom environment, and setup file
  • Created with for Vite 8 oxc transform
  • Installed missing peer dependency
  • Deleted empty that was shadowing

Blocked

  • Pre-commit hook () fails due to a pre-existing ESLint syntax error in ( selector). Committed with since the error is not caused by these changes.

…g buffers, realtime cache invalidation

Closes Refract-Protocol#251 — Throttled ARIA live region system (AriaLiveProvider + useAriaLive)
  - aria-live=polite, atomic, visually hidden
  - 2s throttle window (5s with prefers-reduced-motion)
  - Batch coalescing: multiple messages in the same tick joined into one announcement

Closes Refract-Protocol#252 — Horizon SSE streaming for transaction history
  - streamOperations() uses EventSource on /accounts/{address}/operations with cursor=now
  - useTransactionHistory: initial REST page, then live SSE updates prepended (de-duped by id)
  - loadMore still uses REST cursor pagination for older pages

Closes Refract-Protocol#253 — Bounded per-topic ring buffers for realtime events
  - RingBuffer<T> class with documented capacity, push (evicts oldest), latest, toArray, clear
  - RealtimeClient now buffers each topic in a RingBuffer with caps from TOPIC_BUFFER_CAPS
  - topics.ts: REALTIME_TOPICS, TOPIC_BUFFER_CAPS, TOPIC_TO_QUERY_KEYS, TOPIC_ANNOUNCEMENTS

Closes Refract-Protocol#254 — Wire realtime events into shared cache
  - RealtimeSyncProvider subscribes to all topics and calls queryClient.invalidateQueries
  - Also announces via AriaLiveProvider so screen readers learn about changes
  - providers.tsx: QueryClientProvider > AriaLiveProvider > RealtimeSyncProvider > WalletProvider

Tests: 33 new tests (ringBuffer 12, AriaLive 6, horizonSse 8, realtimeSync 7) — all passing.
Pre-existing: typecheck (12 errors in cover/page.tsx), build (same file), lint (cover/compare/page.tsx).
Fixed: vitest config now includes .tsx tests, jsdom env, setup file, tsconfig.test.json for JSX.
Installed missing @testing-library/dom peer dep. Deleted empty vitest.config.ts shadowing .mts.
@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

@edwardmiracle916-wq Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant