UNPKG

@instantdb/core

Version:

Instant's core local abstraction

118 lines (97 loc) 2.81 kB
import { pick } from './utils/pick.js'; import { areObjectsShallowEqual, areObjectKeysEqual } from './utils/object.js'; export type RoomSchemaShape = { [k: string]: { presence?: { [k: string]: any }; topics?: { [k: string]: { [k: string]: any; }; }; }; }; export type PresenceOpts<PresenceShape, Keys extends keyof PresenceShape> = { user?: boolean; peers?: string[]; keys?: Keys[]; // Initial presence data to set when joining the room initialData?: Partial<PresenceShape>; }; type PresencePeer<PresenceShape, Keys extends keyof PresenceShape> = Pick< PresenceShape, Keys > & { peerId: string; }; export type PresenceSlice<PresenceShape, Keys extends keyof PresenceShape> = { user?: PresencePeer<PresenceShape, Keys>; peers: { [peerId: string]: PresencePeer<PresenceShape, Keys>; }; }; export type PresenceResponse< PresenceShape, Keys extends keyof PresenceShape, > = PresenceSlice<PresenceShape, Keys> & { isLoading: boolean; error?: string; }; export function buildPresenceSlice< PresenceShape, Keys extends keyof PresenceShape, >( data: { user?: PresenceShape; peers: Record<string, PresenceShape>; }, opts: PresenceOpts<PresenceShape, Keys>, userPeerId: string, ): PresenceSlice<PresenceShape, Keys> { const slice: PresenceSlice<PresenceShape, Keys> = { peers: {}, }; const includeUser = opts && 'user' in opts ? opts.user : true; if (includeUser) { const user = pick(data.user ?? {}, opts?.keys); slice.user = { ...user, peerId: userPeerId }; } for (const id of Object.keys(data.peers ?? {})) { const shouldIncludeAllPeers = opts?.peers === undefined; const isPeerIncluded = Array.isArray(opts?.peers) && opts?.peers.includes(id); if (shouldIncludeAllPeers || isPeerIncluded) { const peer = pick(data.peers[id], opts?.keys); slice.peers[id] = { ...peer, peerId: id }; } } return slice; } /** * Compare two presence slices * 0. compare isLoading and error * 1. shallow compare user * 2. compare peers keys * 3. shallow compare each peer */ export function hasPresenceResponseChanged< PresenceShape, Keys extends keyof PresenceShape, >( a: PresenceResponse<PresenceShape, Keys>, b: PresenceResponse<PresenceShape, Keys>, ) { if (a.isLoading !== b.isLoading) return true; if (a.error !== b.error) return true; if (a.user || b.user) { if (!a.user || !b.user) return true; const same = areObjectsShallowEqual(a.user, b.user); if (!same) return true; } const sameKeys = areObjectKeysEqual(a.peers, b.peers); if (!sameKeys) return true; for (const id of Object.keys(a.peers)) { const same = areObjectsShallowEqual(a.peers[id], b.peers[id]); if (!same) return true; } return false; }