Skip to content

feat(realtime): Broadcast facade, firebase-database/polling/memory transports and device push - #10

Merged
3m1n3nc3 merged 1 commit into
mainfrom
feat/realtime-transports
Oct 10, 2026
Merged

3m1n3nc3 merged 1 commit into
mainfrom
feat/realtime-transports

Conversation

@3m1n3nc3

Copy link
Copy Markdown
Member

Summary

Extends @arkstack/notifications and @arkstack/realtime so apps can run all their realtime on Arkstack, not only per-user notifications.

Added

  • Broadcast facade (@arkstack/notifications)
    • Channel authorization registry: Broadcast.channel('private-team.{teamId}', (user, params) => ...). Placeholders match one dot-free segment, the first matching rule decides, and unmatched channels are denied. The per-user channel stays allowed for its own user.
    • broadcast() for arbitrary events, handleAuth() for custom auth routes (e.g. guest tokens), clientConfig(), and routes() registering POST /realtime/auth and GET /realtime/config.
  • New transports, on both server and client:
    • firebase-database: Realtime Database channels. Per-user grants expire after a TTL and are checked by security rules; prune() deletes old events in bounded batches.
    • polling: signal-only. Clients refetch through RealtimeClient.onPoll().
    • memory: for tests. Shared on globalThis so it works across module graphs.
  • Device push separate from streaming
    • Set drivers.realtime.push: 'firebase'. Tokens come from a push_tokens resolver or user.pushTokens.
    • Per send: .push(false) skips the push, .devices(tokens) targets specific devices, and the multicast outcome is on result.push.
    • Client gets deviceToken().
  • Self-hosted Pusher-protocol servers (soketi): transports.pusher.host/port on the server, wsHost/wsPort on the client.

Fixed

  • UserNotificationCenter.send() and Notification.db().broadcast() broadcast on the user's channel. Before, they used push tokens as channel names, so users without tokens got nothing.
  • Notification.db().broadcast() now returns the builder, so the documented chain works.
  • The Pusher auth route from registerAuthRoute():
    • returns HTTP 200, since pusher-js rejects anything else;
    • registers H3 on @arkstack/driver-h3;
    • authorizes through the registry.

Compatibility

  • When drivers.realtime.push is unset and the transport is firebase, notifications still reach users' devices.
  • Breaking: an unknown transport name now throws when the notification is constructed. Before, it fell back to Pusher.
  • PUSHER_HOST / PUSHER_PORT are now read from env.
  • RealtimeDriverName and RealtimeTransportName gain members, so exhaustive switches over them need new cases.

Docs

  • Notifications guide: transports, channel authorization, device push, Realtime Database rules and pruning, polling, testing.
  • Scaffold templates and the changelog are updated.

Test plan

  • vitest run: 73 files, all passing.
  • tsc --noEmit and eslint clean for both packages; both packages build.
  • Express template notifications config typechecks against the new types.
  • Live check against a real soketi server.
  • Live check against Firebase: Realtime Database rules and FCM deviceToken().

…y transports and device push

- Broadcast facade: channel authorization registry shared by every transport,
  broadcast() for arbitrary events, handleAuth(), clientConfig(), and routes()
  registering POST /realtime/auth and GET /realtime/config.
- New transports on server and client: firebase-database (Realtime Database
  channels with time-limited grants and bounded prune), signal-only polling,
  and memory for tests.
- Device push separate from streaming via drivers.realtime.push, with a
  push_tokens resolver, .push(false), .devices(tokens) and result.push.
  Unset push keeps device delivery on for the firebase transport.
- Self-hosted Pusher-protocol servers (soketi) via host/port and wsHost/wsPort.
- Client: onPoll(), deviceToken(), transportName.
- Fix UserNotificationCenter.send() broadcasting to push tokens instead of the
  user channel, db().broadcast() not chaining, and the Pusher auth route
  returning 201 and registering H3 on the Express package.
- Templates, notifications guide and changelog updated.
@3m1n3nc3
3m1n3nc3 merged commit 174d4e3 into main Oct 10, 2026
4 checks passed
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.

1 participant