Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/packages/admin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class Rooms<Schema extends InstantSchemaDef<any, any, any>> {
this.config = config;
}

async getPresence<RoomType extends keyof RoomsOf<Schema>>(
async getPresence<RoomType extends string & keyof RoomsOf<Schema>>(
roomType: RoomType,
roomId: string,
): Promise<PresenceResult<PresenceOf<Schema, RoomType>>> {
Expand Down
34 changes: 26 additions & 8 deletions client/packages/core/src/Reactor.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export default class Reactor {
/** @type BroadcastChannel | undefined */
_broadcastChannel;

/** @type {Record<string, {isConnected: boolean; error: any}>} */
/** @type {Record<string, {roomType: string; isConnected: boolean; error: any}>} */
_rooms = {};
/** @type {Record<string, boolean>} */
_roomsPendingLeave = {};
Expand Down Expand Up @@ -618,7 +618,8 @@ export default class Reactor {

for (const roomId of Object.keys(this._rooms)) {
const enqueuedUserPresence = this._presence[roomId]?.result?.user;
this._tryJoinRoom(roomId, enqueuedUserPresence);
const roomType = this._rooms[roomId]?.roomType;
this._tryJoinRoom(roomType, roomId, enqueuedUserPresence);
}
break;
}
Expand Down Expand Up @@ -2227,15 +2228,17 @@ export default class Reactor {
// Rooms

/**
* @param {string} roomType
* @param {string} roomId
* @param {any | null | undefined} [initialPresence] -- initial presence data to send when joining the room
* @returns () => void
*/
joinRoom(roomId, initialPresence) {
joinRoom(roomType, roomId, initialPresence) {
let needsToSendJoin = false;
if (!this._rooms[roomId]) {
needsToSendJoin = true;
this._rooms[roomId] = {
roomType,
isConnected: false,
error: undefined,
};
Expand All @@ -2250,7 +2253,7 @@ export default class Reactor {
}

if (needsToSendJoin) {
this._tryJoinRoom(roomId, initialPresence);
this._tryJoinRoom(roomType, roomId, initialPresence);
}

return () => {
Expand Down Expand Up @@ -2284,6 +2287,15 @@ export default class Reactor {
getPresence(roomType, roomId, opts = {}) {
const room = this._rooms[roomId];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if someone joins two rooms, different roomType, but same id?

I wonder if now that we are using roomType, we should create a kind of composite key: roomType+roomId

const presence = this._presence[roomId];

if (room?.error) {
return {
...buildPresenceSlice(presence?.result || {}, opts, this._sessionId),
isLoading: false,
error: room.error,
};
}

if (!room || !presence || !presence.result) return null;

return {
Expand Down Expand Up @@ -2326,8 +2338,13 @@ export default class Reactor {
});
}

_tryJoinRoom(roomId, data) {
this._trySendAuthed(uuid(), { op: 'join-room', 'room-id': roomId, data });
_tryJoinRoom(roomType, roomId, data) {
this._trySendAuthed(uuid(), {
op: 'join-room',
'room-type': roomType,
'room-id': roomId,
data,
});
delete this._roomsPendingLeave[roomId];
}

Expand All @@ -2345,6 +2362,7 @@ export default class Reactor {
// TODO: look into typing again
subscribePresence(roomType, roomId, opts, cb) {
const leaveRoom = this.joinRoom(
roomType,
roomId,
// Oct 28, 2025
// Note: initialData is deprecated.
Expand Down Expand Up @@ -2459,8 +2477,8 @@ export default class Reactor {
});
}

subscribeTopic(roomId, topic, cb) {
const leaveRoom = this.joinRoom(roomId);
subscribeTopic(roomType, roomId, topic, cb) {
const leaveRoom = this.joinRoom(roomType, roomId);

this._broadcastSubs[roomId] = this._broadcastSubs[roomId] || {};
this._broadcastSubs[roomId][topic] =
Expand Down
10 changes: 7 additions & 3 deletions client/packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -689,19 +689,23 @@ class InstantCoreDatabase<
* unsubscribeTopic();
* room.leaveRoom();
*/
joinRoom<RoomType extends keyof RoomsOf<Schema>>(
joinRoom<RoomType extends string & keyof RoomsOf<Schema>>(
roomType: RoomType = '_defaultRoomType' as RoomType,
roomId: string = '_defaultRoomId',
opts?: {
initialPresence?: Partial<PresenceOf<Schema, RoomType>>;
},
): RoomHandle<PresenceOf<Schema, RoomType>, TopicsOf<Schema, RoomType>> {
const leaveRoom = this._reactor.joinRoom(roomId, opts?.initialPresence);
const leaveRoom = this._reactor.joinRoom(
roomType,
roomId,
opts?.initialPresence,
);

return {
leaveRoom,
subscribeTopic: (topic, onEvent) =>
this._reactor.subscribeTopic(roomId, topic, onEvent),
this._reactor.subscribeTopic(roomType, roomId, topic, onEvent),
subscribePresence: (opts, onChange) =>
this._reactor.subscribePresence(roomType, roomId, opts, onChange),
publishTopic: (topic, data) =>
Expand Down
2 changes: 1 addition & 1 deletion client/packages/core/src/presence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export type PresenceResponse<
Keys extends keyof PresenceShape,
> = PresenceSlice<PresenceShape, Keys> & {
isLoading: boolean;
error?: string;
error?: { message: string; type: string };
};

export function buildPresenceSlice<
Expand Down
11 changes: 11 additions & 0 deletions client/packages/core/src/rulesTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ type InstantRulesAttrsAllowBlock = {
delete?: string | null | undefined;
};

type InstantRoomRulesAllowBlock = {
$default?: string | null | undefined;
join?: string | null | undefined;
};

export type InstantRulesAllowBlock = InstantRulesAttrsAllowBlock & {
link?: { [key: string]: string } | null | undefined;
unlink?: { [key: string]: string } | null | undefined;
Expand All @@ -24,6 +29,12 @@ export type InstantRules<
bind?: string[] | Record<string, string>;
allow: InstantRulesAttrsAllowBlock;
};
$rooms?: {
[RoomType: string]: {
bind?: string[] | Record<string, string>;
allow: InstantRoomRulesAllowBlock;
};
};
} & {
[EntityName in keyof Schema['entities']]?: {
bind?: string[] | Record<string, string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export default abstract class InstantReactAbstractDatabase<
* const room = db.room('chat', roomId);
* const { peers } = db.rooms.usePresence(room);
*/
room<RoomType extends keyof Rooms>(
room<RoomType extends string & keyof Rooms>(
type: RoomType = '_defaultRoomType' as RoomType,
id: string = '_defaultRoomId',
) {
Expand Down
20 changes: 12 additions & 8 deletions client/packages/react-common/src/InstantReactRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const defaultActivityStopTimeout = 1_000;
*/
export function useTopicEffect<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
TopicType extends keyof RoomSchema[RoomType]['topics'],
>(
room: InstantReactRoom<any, RoomSchema, RoomType>,
Expand All @@ -76,6 +76,7 @@ export function useTopicEffect<

useEffect(() => {
const unsub = room.core._reactor.subscribeTopic(
room.type,
room.id,
topic,
(event, peer) => {
Expand Down Expand Up @@ -104,13 +105,13 @@ export function useTopicEffect<
*/
export function usePublishTopic<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
TopicType extends keyof RoomSchema[RoomType]['topics'],
>(
room: InstantReactRoom<any, RoomSchema, RoomType>,
topic: TopicType,
): (data: RoomSchema[RoomType]['topics'][TopicType]) => void {
useEffect(() => room.core._reactor.joinRoom(room.id), [room.id]);
useEffect(() => room.core._reactor.joinRoom(room.type, room.id), [room.id]);

const publishTopic = useCallback(
(data) => {
Expand Down Expand Up @@ -146,7 +147,7 @@ export function usePublishTopic<
*/
export function usePresence<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
Keys extends keyof RoomSchema[RoomType]['presence'],
>(
room: InstantReactRoom<any, RoomSchema, RoomType>,
Expand Down Expand Up @@ -203,13 +204,16 @@ export function usePresence<
*/
export function useSyncPresence<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
>(
room: InstantReactRoom<any, RoomSchema, RoomType>,
data: Partial<RoomSchema[RoomType]['presence']>,
deps?: any[],
): void {
useEffect(() => room.core._reactor.joinRoom(room.id, data), [room.id]);
useEffect(
() => room.core._reactor.joinRoom(room.type, room.id, data),
[room.id],
);
useEffect(() => {
return room.core._reactor.publishPresence(room.type, room.id, data);
}, [room.type, room.id, deps ?? JSON.stringify(data)]);
Expand All @@ -236,7 +240,7 @@ export function useSyncPresence<
*/
export function useTypingIndicator<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
>(
room: InstantReactRoom<any, RoomSchema, RoomType>,
inputName: string,
Expand Down Expand Up @@ -320,7 +324,7 @@ export const rooms = {
export class InstantReactRoom<
Schema extends InstantSchemaDef<any, any, any>,
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
> {
core: InstantCoreDatabase<Schema, boolean>;
/** @deprecated use `core` instead */
Expand Down
2 changes: 1 addition & 1 deletion client/packages/react/src/Cursors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { RoomSchemaShape } from '@instantdb/core';

export function Cursors<
RoomSchema extends RoomSchemaShape,
RoomType extends keyof RoomSchema,
RoomType extends string & keyof RoomSchema,
>({
as = 'div',
spaceId: _spaceId,
Expand Down
Loading