@netless/synced-store v2.0.9
SyncedStore
A white-web-sdk plugin for storing shared replayable states and sending/receiving replayable events.
Install
npm add @netless/synced-storeExample
Init SyncedStore right after joining room:
import { createSyncedStorePlugin } from "@netless/synced-store";
const SyncedStorePlugin = createSyncedStorePlugin();
const whiteboard = new WhiteWebSdk({
appIdentifier: "xxxxxxxxxxxxxx",
useMobXState: true, // This is required to use SyncedStorePlugin
deviceType: DeviceType.Surface,
});
const room = await whiteboard.joinRoom({
uuid: roomUUID,
roomToken: roomToken,
uid: userID,
invisiblePlugins: [SyncedStorePlugin],
// Only writable users can modify states and dispatch events.
// Set this to false for readonly users(audience) for better performance
isWritable: true,
});
// Define typed event keys and payloads
type EventData = {
"click-event": { id: string };
};
const syncedStore = await SyncedStorePlugin.init<EventData>(room);interface State {
count: number;
}
// connect to a namespaced storage
const storage = await syncedStore.connectStorage<State>("a-name", { count: 0 });
storage.state; // => { count: 0 }
if (storage.isWritable) {
storage.setState({ count: 2 });
}
const stateChangedDisposer = storage.on("stateChanged", diff => {
if (diff.count) {
// count: 0 -> 2
console.log("count:", diff.count.oldValue, "->", diff.count.newValue);
console.log(diff.count.newValue === app.state.count);
}
});
if (syncStore.isRoomWritable) {
syncedStore.dispatchEvent("click-event", { id: "item1" });
}
const eventDisposer = syncedStore.addEventListener(
"click-event",
({ payload }) => {
console.log(payload.id); // item1
}
);Develop
Add .env at project root following the .env.example reference.
pnpm i
pnpm startTesting
Unit Test:
pnpm tEnd-to-end Test:
- Start hosting the testing resources
pnpm e2e:page - Then then open a new terminal to start e2e tests
pnpm e2e
API
static SyncedStorePlugin.init(room)
A
staticmethod that inits the SyncedStore. Should be called right after joining room.Returns:
Promise<SyncedStore<EventData>>SyncedStore.isRoomWritable
Type:
booleanShortcut to whiteboard room writable state. When it is
false, callingstorage.setState()anddispatchEvent()will throw errors.SyncedStore.setRoomWritable(isWritable)
Shortcut to change whiteboard room writable state.
SyncedStore.addRoomWritableChangeListener(listener)
It fires when whiteboard room writable state changes.
Type:
(isRoomWritable: boolean) => voidReturns:
() => void- a disposable function that can be called to remove the listener.SyncedStore.isPluginWritable
Type:
booleanIt is
trueifisRoomWritable === trueand plugin finished initialization. When it isfalse, callingstorage.setState()will throw errors.SyncedStore.addPluginWritableChangeListener(listener)
It fires when plugin writable state changes.
Type:
(isPluginWritable: boolean) => voidReturns:
() => void- a disposable function that can be called to remove the listener.SyncedStore.dispatchEvent(event, payload)
Broadcast an event message to other clients.
syncedStore.dispatchEvent("click", { data: "data" });SyncedStore.addEventListener(event, listener)
It fires when receiving messages from other clients (when other clients called
syncedStore.dispatchEvent()).Returns:
() => voida disposer function.const disposer = syncedStore.addEventListener( "click-event", ({ payload }) => { console.log(payload.data); disposer(); } ); syncedStore.dispatchEvent("click-event", { data: "data" });SyncedStore.connectStorage(namespace, defaultState)
Connect to a namespaced storage. Each call returns an fresh storage instance with its own life-cycle. Calling multiple times with same namespace will result in different storage instances sharing the same data.
namespace
Name for the storage. Storages with the same namespace share the same state(but each storage instance keeps it own life-cycle).
Type:
stringdefaultState
Type:
StateReturns:
Storage<State>const storage = syncedStore.connectStorage("my-storage", { count: 0 });Storage.state
Type:
StateDefault:
initialStateThe synchronized state across all clients. To change it, call
storage.setState().Storage.setState(partialState)
Works like React's
setState, it updatesstorage.stateand synchronize it to other clients.When some field's value is
undefined, it will be removed fromstorage.state.Important: Do not rely on the order of state changes:
storage.setState()altersstorage.statesynchronously butonStateChangedwill wait until the data is successfully synced.- State syncing time span varies due to network status and data size. It is recommended to store only necessary data in the store.
partialState
Type:
Partial<State>storage.state; //=> { count: 0, a: 1 } storage.setState({ count: storage.state.count + 1, a: undefined, b: 2 }); storage.state; //=> { count: 1, b: 2 }Storage.on("stateChanged", listener)
A state changed event that fires after someone called
storage.setState()(including the current syncedStore itself).Returns:
() => void- A disposable function that can be called to remove the listener.const disposer = storage.on("stateChanged", diff => { console.log("state changed", diff.oldValue, diff.newValue); disposer(); // remove listener by calling disposer });Storage.on("disconnected", listener)
An event that fires after the storage instance is disconnected.
Returns:
() => void- A disposable function that can be called to remove the listener.const disposer = storage.on("disconnected", () => { console.log(storage.disconnected); // true });Stoarge.disconnect()
Disconnect or dispose the storage, triggers
disconnectedevent, and release all listeners.
License
MIT @ netless
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago