ngrx-signals-broadcast-sync

Enables seamless synchronization of state between browser contexts

MIT License

Downloads
53
Stars
0

Installation

To install the library via npm:

npm install @ricardojbd/ngrx-signals-broadcast-sync

Ensure you are using @ngrx/signals version v18.0.0 or later.

[!WARNING] This library only functions in browser environments. It falls back to a stub implementation in server environments, such as Angular Universal.

Usage

To use the library, simply apply the withBroadcastSync() function, passing the channel name:

import { signalStore, withState } from '@ngrx/signals';
import { withBroadcastSync } from '@ricardojbd/ngrx-signals-broadcast-sync';

export const UserStore = signalStore(
  withState({ user: null }), 
  withBroadcastSync('user@store')
);

Advanced Configuration

You can also pass an Options object instead of a string channel for more control. The Options object supports the following:

  • channel: (Required) The name of the broadcast channel used for state synchronization. This is the unique identifier for the communication channel between clients, allowing them to broadcast and receive state updates.
  • select: (Optional) Function to select a portion of the state to broadcast. This function can be used to limit the slice of the state that is sent over the broadcast channel by selecting only the relevant parts of the state. By default, the entire state is selected and broadcasted as (state) => state.
  • requestState: (Optional) If true, the store will request the current state from other connected clients on initialization. This is useful when a new client connects and needs to recover the current state from other connected clients, ensuring that it is synchronized with the latest state. The default value is false.
  • messageEventInterceptor: (Optional) Interceptor for handling incoming broadcast messages. This function allows you to process or modify the incoming broadcast message before it is handled by the store. By default, the function extracts and returns the message's data as (event) => event.data.
  • broadcastStateInterceptor: (Optional) Interceptor for modifying the state before it is broadcasted. This function is called before the state is sent through the broadcast channel. It allows for any necessary modifications to the state before broadcasting it. By default, it returns the state as-is (state) => state.
  • onMessageError: (Optional) Callback invoked when an error occurs while receiving a message from the broadcast channel. This function handles errors that occur when receiving messages. You can use it to log errors or perform other error handling actions. By default, no action is taken (event) => null.
import { signalStore, withState } from '@ngrx/signals';
import { withBroadcastSync } from '@ricardojbd/ngrx-signals-broadcast-sync';

type User = { user: string | null, roles?: string[] }

export const UserStore = signalStore(
  withState<User>({ user: null, roles: [] }), 
  withBroadcastSync({ 
    channel: 'user@store',
    requestState: true,
    select: (state) => ({ user: state.user }),
    messageEventInterceptor: (event) => {
      console.log('message', event);
      return event.data;
    },
    broadcastStateInterceptor: (state) => {
      console.log('broadcast', state);
      return state;
    },
    onMessageError: (event) => console.error(event),
  })
);

API Methods

Once withBroadcastSync is applied, it exposes two methods for working with the broadcast system:

  • getBroadcastChannel(): Retrieves the current BroadcastChannel used for synchronizing state or null if the channel is not available or has not been initialized.
  • broadcastState(): Sends the current state of the store through the broadcast channel to other connected clients. By default, it is triggered when a state change requires synchronization, but you can manually force a broadcast by invoking this method.
@Component(...)
public class UserStoreComponent {
  readonly #store: UserStore = inject(UserStore);
  readonly channel: BroadcastChannel | null = this.#store.getBroadcastChannel()

  broadcastState(): void {
    this.#store.broadcastState();
  }
}

Development Setup

We welcome all contributions, from bug fixes to new features!

Getting Started

  • Install Node.js.
  • Use pnpm for dependency management and task automation.
  • Test features using the included playground app.

Contribution Workflow

  1. Follow the GitHub Flow: Fork the repo, create a branch, and document changes.
  2. Ensure thorough testing with unit, integration, and E2E tests.
  3. Submit a detailed pull request.
  4. Follow the Code of Conduct.

For bugs and feature requests, use GitHub Issues.

License

This library is adapted from Elf Sync State and is inspired by the withStorageSync feature in the NgRx Toolkit.

The logo is an adaptation of the NgRx logo, originally available from the NgRx press page under the CC BY 4.0 license. This modified version follows the same license CC BY 4.0.