Skip to content

[2.x] feat: realtime extender API + per-extension integrations + notification toasts - #4473

Merged
imorland merged 9 commits into
2.xfrom
im/realtime-extender-refactor
Mar 20, 2026
Merged

[2.x] feat: realtime extender API + per-extension integrations + notification toasts#4473
imorland merged 9 commits into
2.xfrom
im/realtime-extender-refactor

Conversation

@imorland

Copy link
Copy Markdown
Member

Summary

  • Introduces a Realtime PHP + JS extender so bundled extensions wire their own realtime behaviour; flarum/realtime has no hardcoded knowledge of other extensions
  • Moves realtime push integrations into flarum/flags, flarum/likes, flarum/lock, and flarum/messages respectively
  • Adds realtime notification toasts: incoming push notifications show as auto-dismissing popups (top-right, 5 s) reusing the standard NotificationType component with discussion context
  • Fixes inline message delivery in flarum/messages (push not reload) and typing indicator teardown
  • Adds NotificationResource::Show endpoint and Notification to Generator endpoint map so notification payloads are generated correctly
  • Deletes dead NewActivity push classes from flarum/realtime

Test plan

  • CI passes
  • Likes realtime update in discussion
  • Lock/unlock realtime update
  • Flags realtime update (flag count + flagged post border)
  • Messages: new message appears inline; typing indicator shown/hidden; dialog list refreshes
  • Notification toast appears top-right on incoming notification, auto-dismisses after 5 s, shows discussion context header
  • No data leakage: notification payload gated by user_id = actor->id scope in both DB query and API resource

imorland and others added 2 commits March 20, 2026 23:22
…fication toasts

Introduces a `Realtime` extender so each bundled extension wires its own
realtime behaviour without realtime having hardcoded knowledge of them.

**flarum/realtime**
- New `Realtime` PHP extender: `onPublicChannelEvent`, `onUserChannelEvent`,
  `registerModelEndpoint` — extensions declare their own push handlers and
  payload model mappings.
- `RealtimeRegistry` collects extender registrations; `EventSubscriber`
  dispatches them.
- `Generator` endpoint/resource maps are now open — `Notification` added as
  a core entry; extensions add their own via `registerModelEndpoint`.
- Deleted hardcoded `NewActivity` push classes (Dialog, Discussion, Post).
- `SendFlaggedJob` no longer deletes flags as a side-effect; flags extension
  owns that logic.
- `SendNotificationsJob` now looks up the `Notification` record and sends it
  (not the recipient `User`) so the JS receives a proper notification payload.
- JS: new `Realtime` extender class for extension-side channel event wiring.
- JS: `RealtimeState` for sharing channel-ready callbacks.
- JS: `NotificationToast` component + `NotificationToastState` — realtime
  notifications show as auto-dismissing toasts (top-right, 5 s) reusing the
  standard `NotificationType` component, with discussion context header.
- LESS: toast + typing-indicator styles.

**flarum/flags**
- Registers its own realtime push via `Realtime` extender (flagged event).
- JS: `extendRealtime` wires flag stream update on incoming flag events.

**flarum/likes**
- Registers its own realtime push via `Realtime` extender.
- JS converted to TypeScript; `extendRealtime` wires like count update.

**flarum/lock**
- Registers its own realtime push via `Realtime` extender.
- JS converted to TypeScript; `extendRealtime` wires lock state update.

**flarum/messages**
- Registers its own realtime push via `Realtime` extender.
- JS: `extendRealtime` wires inline message delivery (`state.push`) and
  typing indicator; uses `ext:` prefix for cross-extension `extend()` calls.
- `DialogMessageResource` gains a Show endpoint (needed for payload generation).
- `extend.php` de-duplicated (Show endpoint lives in resource class).

**flarum/core**
- `NotificationResource` gains a Show endpoint (authenticated, scoped to
  actor) so the payload generator can fetch a single notification.
@imorland imorland added this to the 2.0.0-beta.8 milestone Mar 20, 2026
imorland and others added 7 commits March 20, 2026 23:29
- Generator::retrieve(): add is_string() guard before instanceof to fix
  PHPStan error (map keys are int|string, instanceof requires string)
- Improve TypeScript type coverage from 76% → 80%: replace `this: any`
  property assignments with arrow functions so inner callbacks are typed;
  add explicit return types and typed parameters to DiscussionList/NewActivity,
  Discussion/NewActivity, and Discussion/TypingIndicator
imorland added a commit to flarum/docs that referenced this pull request Mar 20, 2026
Documents the Realtime PHP and JS extender API introduced in
flarum/framework#4473. Covers:

- broadcastModelEvent / broadcastDialogEvent / broadcastFlagEvent
- registerModelEndpoint for custom model types
- JS RealtimeExtend extender (onDiscussionStreamEvent, onUserChannelEvent,
  onPublicChannelEvent, onBothChannelsEvent)
- Direct channel access via RealtimeState
- Complete likes integration as a real-world example
- Security model (permission-gated payload generation + channel auth)
@imorland
imorland marked this pull request as ready for review March 20, 2026 23:57
@imorland
imorland requested a review from a team as a code owner March 20, 2026 23:57
@imorland
imorland merged commit cd4316a into 2.x Mar 20, 2026
25 checks passed
@imorland
imorland deleted the im/realtime-extender-refactor branch March 20, 2026 23:58
imorland added a commit to flarum/docs that referenced this pull request Mar 21, 2026
Documents the Realtime PHP and JS extender API introduced in
flarum/framework#4473. Covers:

- broadcastModelEvent / broadcastDialogEvent / broadcastFlagEvent
- registerModelEndpoint for custom model types
- JS RealtimeExtend extender (onDiscussionStreamEvent, onUserChannelEvent,
  onPublicChannelEvent, onBothChannelsEvent)
- Direct channel access via RealtimeState
- Complete likes integration as a real-world example
- Security model (permission-gated payload generation + channel auth)
imorland added a commit that referenced this pull request Mar 21, 2026
These were generated by the TS build during the realtime refactor (#4473)
but never committed — the build bot only updates already-tracked files.
This seeds the dist-typings so future PRs are bundled automatically.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants