improve index usage

This commit is contained in:
2026-03-31 14:09:55 -04:00
parent 4f586a8495
commit 275096730b
22 changed files with 512 additions and 576 deletions
+47 -2
View File
@@ -84,9 +84,17 @@ const voice_activity = table(
{
name: "voice_activity",
public: true,
indexes: [
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
identity: t.identity().primaryKey(),
channel_id: t.u64(),
is_talking: t.bool(),
},
);
@@ -98,6 +106,11 @@ const watching = table(
indexes: [
{ accessor: "by_watcher", algorithm: "btree", columns: ["watcher"] },
{ accessor: "by_watchee", algorithm: "btree", columns: ["watchee"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -116,6 +129,11 @@ const voice_sdp_offer = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -134,6 +152,11 @@ const voice_sdp_answer = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -152,6 +175,11 @@ const voice_ice_candidate = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -171,6 +199,11 @@ const screen_sdp_offer = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -189,6 +222,11 @@ const screen_sdp_answer = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -207,6 +245,11 @@ const screen_ice_candidate = table(
indexes: [
{ accessor: "by_receiver", algorithm: "btree", columns: ["receiver"] },
{ accessor: "by_sender", algorithm: "btree", columns: ["sender"] },
{
accessor: "by_channel_id",
algorithm: "btree",
columns: ["channel_id"],
},
],
},
{
@@ -296,17 +339,19 @@ export const set_name = spacetimedb.reducer(
);
export const set_talking = spacetimedb.reducer(
{ talking: t.bool() },
(ctx, { talking }) => {
{ talking: t.bool(), channelId: t.u64() },
(ctx, { talking, channelId }) => {
const activity = ctx.db.voice_activity.identity.find(ctx.sender);
if (activity) {
ctx.db.voice_activity.identity.update({
identity: ctx.sender,
channel_id: channelId,
is_talking: talking,
});
} else {
ctx.db.voice_activity.insert({
identity: ctx.sender,
channel_id: channelId,
is_talking: talking,
});
}
+14 -1
View File
@@ -85,6 +85,7 @@ const ChatContainer: React.FC = () => {
watching={watching}
peerStats={peerStats}
setPeerAudioPreference={setPeerAudioPreference}
voiceActivity={chat.voiceActivity}
/>
{/* Voice Connected Status Bar */}
{chat.connectedVoiceChannel && (
@@ -201,6 +202,9 @@ const ChatContainer: React.FC = () => {
startWatching={startWatching}
stopWatching={stopWatching}
watching={watching}
users={chat.users}
voiceStates={chat.voiceStates}
voiceActivity={chat.voiceActivity}
/>
) : (
<>
@@ -212,6 +216,7 @@ const ChatContainer: React.FC = () => {
identity={identity ?? null}
handleStartThread={chat.handleStartThread}
isFullyAuthenticated={chat.isFullyAuthenticated}
allThreads={chat.allThreads}
/>
<MessageInput
activeChannelId={chat.activeChannelId}
@@ -232,6 +237,8 @@ const ChatContainer: React.FC = () => {
isFullyAuthenticated={chat.isFullyAuthenticated}
users={chat.users}
identity={identity ?? null}
allThreads={chat.allThreads}
allMessages={chat.allMessages}
/>
) : (
showMemberList && (
@@ -243,6 +250,7 @@ const ChatContainer: React.FC = () => {
voiceStates={chat.voiceStates}
currentVoiceState={chat.currentVoiceState}
connectedVoiceChannel={chat.connectedVoiceChannel}
voiceActivity={chat.voiceActivity}
/>
)
)}
@@ -256,7 +264,12 @@ const ChatContainer: React.FC = () => {
/>
)}
{showSettings && <SettingsPanel onClose={() => setShowSettings(false)} />}
{showSettings && (
<SettingsPanel
currentUser={chat.currentUser}
onClose={() => setShowSettings(false)}
/>
)}
</div>
);
};
+3 -5
View File
@@ -1,7 +1,6 @@
import React from "react";
import { Identity } from "spacetimedb";
import { tables } from "../../module_bindings";
import { useTable, useSpacetimeDB } from "spacetimedb/react";
import { useSpacetimeDB } from "spacetimedb/react";
import * as Types from "../../module_bindings/types";
import { WebRTCStats } from "../services";
@@ -18,6 +17,7 @@ interface ChannelListProps {
currentVoiceState: Types.VoiceState | undefined;
connectedVoiceChannel: Types.Channel | undefined;
isFullyAuthenticated: boolean;
voiceActivity: readonly Types.VoiceActivity[];
// Modal state and handlers
showCreateChannelModal: boolean;
@@ -211,6 +211,7 @@ export const ChannelList: React.FC<ChannelListProps> = ({
currentVoiceState,
connectedVoiceChannel,
isFullyAuthenticated,
voiceActivity,
showCreateChannelModal,
setShowCreateChannelModal,
newChannelName,
@@ -226,9 +227,6 @@ export const ChannelList: React.FC<ChannelListProps> = ({
peerStats,
setPeerAudioPreference,
}) => {
const [voiceActivity] = useTable(
React.useMemo(() => tables.voice_activity, []),
);
const [hoveredPeer, setHoveredPeer] = React.useState<string | null>(null);
const [showServerDropdown, setShowServerDropdown] = React.useState(false);
const [contextMenu, setContextMenu] = React.useState<{
+2 -3
View File
@@ -2,8 +2,6 @@
import React, { useMemo } from "react";
import { Identity } from "spacetimedb";
import type * as Types from "../../module_bindings/types";
import { useTable } from "spacetimedb/react";
import { tables } from "../../module_bindings";
// Helper function (extracted from App.tsx)
const getUsername = (
@@ -23,6 +21,7 @@ interface MemberListProps {
voiceStates: readonly Types.VoiceState[];
currentVoiceState: Types.VoiceState | undefined;
connectedVoiceChannel: Types.Channel | undefined;
voiceActivity: readonly Types.VoiceActivity[];
}
function MemberList({
@@ -33,8 +32,8 @@ function MemberList({
voiceStates,
currentVoiceState,
connectedVoiceChannel,
voiceActivity,
}: MemberListProps) {
const [voiceActivity] = useTable(useMemo(() => tables.voice_activity, []));
// Categorize members into Online and Offline
const onlineMembers = useMemo(
() => activeServerMembers.filter((m) => m.online),
+2 -5
View File
@@ -2,8 +2,6 @@
import React, { useRef, useEffect, useMemo } from "react";
import { Identity } from "spacetimedb";
import type * as Types from "../../module_bindings/types";
import { useTable } from "spacetimedb/react";
import { tables } from "../../module_bindings";
import RichText from "./RichText";
@@ -30,6 +28,7 @@ interface MessageListProps {
identity: Identity | null;
handleStartThread: (msg: Types.Message) => void;
isFullyAuthenticated: boolean;
allThreads: readonly Types.Thread[];
}
function MessageList({
@@ -40,6 +39,7 @@ function MessageList({
identity,
handleStartThread,
isFullyAuthenticated,
allThreads,
}: MessageListProps) {
const messagesEndRef = useRef<HTMLDivElement>(null);
@@ -48,9 +48,6 @@ function MessageList({
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
// Fetch threads to display thread links
const [allThreads] = useTable(useMemo(() => tables.thread, []));
return (
<div className="message-list">
{messages.map((msg) => {
-2
View File
@@ -2,8 +2,6 @@
import React, { useState, useMemo } from "react";
import { Identity } from "spacetimedb";
import type * as Types from "../../module_bindings/types";
import { useTable, useReducer } from "spacetimedb/react"; // Assuming useTable and useReducer are available
import { tables, reducers } from "../../module_bindings";
// Helper function (extracted from App.tsx)
const getUsername = (userIdentity: Identity | null, users: Types.User[]) => {
+8 -6
View File
@@ -1,16 +1,18 @@
import React, { useState } from "react";
import { useReducer, useSpacetimeDB, useTable } from "spacetimedb/react";
import { reducers, tables } from "../../module_bindings";
import { useReducer, useSpacetimeDB } from "spacetimedb/react";
import { reducers } from "../../module_bindings";
import * as Types from "../../module_bindings/types";
interface SettingsPanelProps {
onClose: () => void;
currentUser: Types.User | undefined;
}
export const SettingsPanel: React.FC<SettingsPanelProps> = ({ onClose }) => {
export const SettingsPanel: React.FC<SettingsPanelProps> = ({
onClose,
currentUser,
}) => {
const { identity } = useSpacetimeDB();
const [users] = useTable(tables.user);
const currentUser = users.find((u) => u.identity.isEqual(identity!));
const [name, setNameInput] = useState(currentUser?.name || "");
const setNameReducer = useReducer(reducers.setName);
+6 -6
View File
@@ -2,8 +2,8 @@
import React, { useState, useMemo } from "react";
import { Identity } from "spacetimedb";
import type * as Types from "../../module_bindings/types";
import { useTable, useReducer } from "spacetimedb/react"; // Assuming useTable and useReducer are available
import { tables, reducers } from "../../module_bindings";
import { useReducer } from "spacetimedb/react"; // Assuming useTable and useReducer are available
import { reducers } from "../../module_bindings";
import ThreadMessageList from "./ThreadMessageList";
import ThreadMessageInput from "./ThreadMessageInput";
@@ -15,6 +15,8 @@ interface ThreadViewProps {
isFullyAuthenticated: boolean;
users: readonly Types.User[];
identity: Identity | null;
allThreads: readonly Types.Thread[];
allMessages: readonly Types.Message[];
}
function ThreadView({
@@ -25,15 +27,13 @@ function ThreadView({
isFullyAuthenticated,
users,
identity,
allThreads,
allMessages,
}: ThreadViewProps) {
const sendMessageReducer = useReducer(
useMemo(() => reducers.sendMessage, []),
); // Assuming reducers are accessible
// Fetch all threads and messages
const [allThreads] = useTable(useMemo(() => tables.thread, []));
const [allMessages] = useTable(useMemo(() => tables.message, []));
const activeThread = useMemo(
() => allThreads.find((t) => t.id === activeThreadId),
[allThreads, activeThreadId],
+10 -8
View File
@@ -1,7 +1,6 @@
import React, { useEffect, useRef } from "react";
import { Identity } from "spacetimedb";
import { useTable, useSpacetimeDB } from "spacetimedb/react";
import { tables } from "../../module_bindings";
import { useSpacetimeDB } from "spacetimedb/react";
import * as Types from "../../module_bindings/types";
interface VideoGridProps {
@@ -11,6 +10,9 @@ interface VideoGridProps {
startWatching: (peerIdentity: Identity) => void;
stopWatching: (peerIdentity: Identity) => void;
watching: readonly Types.Watching[];
users: readonly Types.User[];
voiceStates: readonly Types.VoiceState[];
voiceActivity: readonly Types.VoiceActivity[];
}
const VideoTile = ({
@@ -22,6 +24,7 @@ const VideoTile = ({
isWatching,
isSharing,
isHero,
users,
}: {
identity: Identity;
stream?: MediaStream;
@@ -31,10 +34,10 @@ const VideoTile = ({
isWatching?: boolean;
isSharing?: boolean;
isHero?: boolean;
users: readonly Types.User[];
}) => {
const videoRef = useRef<HTMLVideoElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [users] = useTable(tables.user);
const [isMuted, setIsMuted] = React.useState(false);
const [volume, setVolume] = React.useState(1.0);
const user = users.find((u) => u.identity.isEqual(identity));
@@ -184,13 +187,11 @@ export const VideoGrid: React.FC<VideoGridProps> = ({
startWatching,
stopWatching,
watching,
users,
voiceStates,
voiceActivity,
}) => {
const { identity: localIdentity } = useSpacetimeDB();
const [voiceStates] = useTable(tables.voice_state);
const [voiceActivity] = useTable(
React.useMemo(() => tables.voice_activity, []),
);
const [users] = useTable(tables.user);
const [focusedIdentity, setFocusedIdentity] = React.useState<Identity | null>(
null,
);
@@ -259,6 +260,7 @@ export const VideoGrid: React.FC<VideoGridProps> = ({
isSharing={isLocal ? localSharing : vs.isSharingScreen}
onToggleWatch={() => toggleWatch(vs.identity)}
isHero={roleClass === "is-hero"}
users={users}
/>
</div>
);
+35 -18
View File
@@ -8,39 +8,44 @@ export const useSubscriptions = (
identity: Identity | null,
activeServerId: bigint | null,
activeChannelId: bigint | null,
connectedVoiceChannelId: bigint | null = null,
) => {
const [servers] = useTable(useMemo(() => tables.server, []));
const [serverMembers] = useTable(
const [activeServerMembers] = useTable(
useMemo(
() =>
activeServerId
? tables.server_member.where((r) => r.serverId.eq(activeServerId))
: tables.server_member,
: tables.server_member.where((r) => r.id.eq(-1n)),
[activeServerId],
),
);
// User's own memberships
useTable(
const [ownMemberships] = useTable(
useMemo(
() =>
identity
? tables.server_member.where((r) => r.identity.eq(identity))
: tables.server_member,
: tables.server_member.where((r) => r.id.eq(-1n)),
[identity],
),
);
const [channels] = useTable(
useMemo(
() =>
activeServerId
? tables.channel.where((r) => r.serverId.eq(activeServerId))
: tables.channel,
[activeServerId],
),
);
const serverMembers = useMemo(() => {
const combined = [...(activeServerMembers || []), ...(ownMemberships || [])];
// De-duplicate
const seen = new Set();
return combined.filter((m) => {
const id = m.id.toString();
if (seen.has(id)) return false;
seen.add(id);
return true;
});
}, [activeServerMembers, ownMemberships]);
const [channels] = useTable(useMemo(() => tables.channel, []));
const [users, isUsersReady] = useTable(useMemo(() => tables.user, []));
@@ -49,7 +54,7 @@ export const useSubscriptions = (
() =>
activeChannelId
? tables.message.where((r) => r.channelId.eq(activeChannelId))
: tables.message,
: tables.message.where((r) => r.id.eq(-1n)),
[activeChannelId],
),
);
@@ -59,21 +64,33 @@ export const useSubscriptions = (
() =>
activeChannelId
? tables.thread.where((r) => r.channelId.eq(activeChannelId))
: tables.thread,
: tables.thread.where((r) => r.id.eq(-1n)),
[activeChannelId],
),
);
const [voiceStates] = useTable(useMemo(() => tables.voice_state, []));
const [voiceActivity] = useTable(
useMemo(
() =>
connectedVoiceChannelId
? tables.voice_activity.where((va) =>
va.channelId.eq(connectedVoiceChannelId),
)
: tables.voice_activity.where((va) => va.identity.eq(Identity.zero())),
[connectedVoiceChannelId],
),
);
return {
servers: servers as readonly Types.Server[],
serverMembers: serverMembers as readonly Types.ServerMember[],
channels: channels as readonly Types.Channel[],
channels: (channels || []) as readonly Types.Channel[],
users: users as readonly Types.User[],
isUsersReady,
allMessages: allMessages as readonly Types.Message[],
allThreads: allThreads as readonly Types.Thread[],
allMessages: (allMessages || []) as readonly Types.Message[],
allThreads: (allThreads || []) as readonly Types.Thread[],
voiceStates: voiceStates as readonly Types.VoiceState[],
voiceActivity: voiceActivity as readonly Types.VoiceActivity[],
};
};
+39 -38
View File
@@ -39,6 +39,7 @@ export interface ChatState {
allMessages: readonly Types.Message[];
allThreads: readonly Types.Thread[];
voiceStates: readonly Types.VoiceState[];
voiceActivity: readonly Types.VoiceActivity[];
currentVoiceState: Types.VoiceState | undefined;
connectedVoiceChannel: Types.Channel | undefined;
onlineUsers: readonly Types.User[];
@@ -119,21 +120,20 @@ export function useChat(): ChatState {
// 2. Setup navigation and subscriptions (order matters)
// We need initial subscriptions to get server list, etc. even before we have an active server.
const {
servers,
serverMembers,
channels,
users,
allMessages,
allThreads,
voiceStates,
} = useSubscriptions(identity || null, null, null);
const bootstrapSubs = useSubscriptions(identity || null, null, null);
const navigation = useNavigation(
identity || null,
servers,
channels,
serverMembers,
bootstrapSubs.servers,
bootstrapSubs.channels,
bootstrapSubs.serverMembers,
);
const voiceStatus = useVoiceStatus(
identity || null,
bootstrapSubs.voiceStates,
bootstrapSubs.channels,
bootstrapSubs.users,
);
// Now we can have specialized subscriptions based on navigation
@@ -143,6 +143,7 @@ export function useChat(): ChatState {
identity || null,
navigation.activeServerId,
navigation.activeChannelId,
voiceStatus.connectedVoiceChannel?.id || null,
);
const actions = useActions(
@@ -151,34 +152,30 @@ export function useChat(): ChatState {
navigation.activeThreadId,
);
const voiceStatus = useVoiceStatus(
identity || null,
voiceStates,
channels,
users,
);
const discovery = useDiscovery();
// Derived Data (Moved back to main orchestrator for now as they use multiple hook results)
const isFullyAuthenticated = useMemo(() => {
const user = users.find((u) =>
const user = activeSubs.users.find((u) =>
u.identity?.isEqual(identity || Identity.zero()),
);
if (!user) return false;
const hasOidc = !!(user.issuer && user.subject);
const hasCreds = !!(user.username && user.password);
return hasOidc || hasCreds;
}, [users, identity]);
}, [activeSubs.users, identity]);
const currentUser = useMemo(
() => users.find((u) => u.identity?.isEqual(identity || Identity.zero())),
[users, identity],
() =>
activeSubs.users.find((u) =>
u.identity?.isEqual(identity || Identity.zero()),
),
[activeSubs.users, identity],
);
const channelMessages = useMemo(
() =>
allMessages
activeSubs.allMessages
.filter(
(m) =>
m.channelId === navigation.activeChannelId &&
@@ -187,22 +184,22 @@ export function useChat(): ChatState {
.sort((a, b) =>
a.sent.microsSinceUnixEpoch < b.sent.microsSinceUnixEpoch ? -1 : 1,
),
[allMessages, navigation.activeChannelId],
[activeSubs.allMessages, navigation.activeChannelId],
);
const threadMessages = useMemo(
() =>
allMessages
activeSubs.allMessages
.filter((m) => m.threadId === navigation.activeThreadId)
.sort((a, b) =>
a.sent.microsSinceUnixEpoch < b.sent.microsSinceUnixEpoch ? -1 : 1,
),
[allMessages, navigation.activeThreadId],
[activeSubs.allMessages, navigation.activeThreadId],
);
const activeThread = useMemo(
() => allThreads.find((t) => t.id === navigation.activeThreadId),
[allThreads, navigation.activeThreadId],
() => activeSubs.allThreads.find((t) => t.id === navigation.activeThreadId),
[activeSubs.allThreads, navigation.activeThreadId],
);
const isActiveChannelVoice = useMemo(
@@ -217,31 +214,33 @@ export function useChat(): ChatState {
const textChannels = useMemo(
() =>
channels.filter(
activeSubs.channels.filter(
(c) =>
c.serverId === navigation.activeServerId && c.kind.tag === "Text",
),
[channels, navigation.activeServerId],
[activeSubs.channels, navigation.activeServerId],
);
const voiceChannels = useMemo(
() =>
channels.filter(
activeSubs.channels.filter(
(c) =>
c.serverId === navigation.activeServerId && c.kind.tag === "Voice",
),
[channels, navigation.activeServerId],
[activeSubs.channels, navigation.activeServerId],
);
const activeServerMembers = useMemo(() => {
if (!navigation.activeServerId) return [];
const memberIdentities = new Set(
serverMembers
activeSubs.serverMembers
.filter((m) => m.serverId === navigation.activeServerId)
.map((m) => m.identity.toHexString()),
);
return users.filter((u) => memberIdentities.has(u.identity.toHexString()));
}, [serverMembers, users, navigation.activeServerId]);
return activeSubs.users.filter((u) =>
memberIdentities.has(u.identity.toHexString()),
);
}, [activeSubs.serverMembers, activeSubs.users, navigation.activeServerId]);
return {
...navigation,
@@ -260,11 +259,13 @@ export function useChat(): ChatState {
textChannels,
voiceChannels,
activeServerMembers,
voiceActivity: activeSubs.voiceActivity,
// Helper functions
getUsername: useCallback(
(userIdentity: Identity | null) => getUsername(userIdentity, users),
[users],
(userIdentity: Identity | null) =>
getUsername(userIdentity, activeSubs.users),
[activeSubs.users],
),
formatTime: useCallback((ts: any) => formatTime(ts), []),
};
@@ -11,9 +11,33 @@ export const useChannelAudioWebRTC = (
isDeafened: boolean,
) => {
const [voiceStates] = useTable(tables.voice_state);
const [offers] = useTable(tables.voice_sdp_offer);
const [answers] = useTable(tables.voice_sdp_answer);
const [iceCandidates] = useTable(tables.voice_ice_candidate);
const [offers] = useTable(
useMemo(
() =>
identity
? tables.voice_sdp_offer.where((o) => o.receiver.eq(identity))
: tables.voice_sdp_offer.where(() => false),
[identity],
),
);
const [answers] = useTable(
useMemo(
() =>
identity
? tables.voice_sdp_answer.where((o) => o.receiver.eq(identity))
: tables.voice_sdp_answer.where(() => false),
[identity],
),
);
const [iceCandidates] = useTable(
useMemo(
() =>
identity
? tables.voice_ice_candidate.where((o) => o.receiver.eq(identity))
: tables.voice_ice_candidate.where(() => false),
[identity],
),
);
const sendSdpOffer = useReducer(reducers.sendVoiceSdpOffer);
const sendSdpAnswer = useReducer(reducers.sendVoiceSdpAnswer);
+6 -6
View File
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect, useCallback } from "react";
import { useReducer } from "spacetimedb/react";
import { reducers } from "../../../module_bindings";
export const useLocalMedia = () => {
export const useLocalMedia = (connectedChannelId: bigint | undefined) => {
const [localStream, setLocalStream] = useState<MediaStream | null>(null);
const [localScreenStream, setLocalScreenStream] =
useState<MediaStream | null>(null);
@@ -94,9 +94,9 @@ export const useLocalMedia = () => {
// Voice Activity Detection
useEffect(() => {
if (!localStream || isMuted || isDeafened) {
if (!localStream || isMuted || isDeafened || !connectedChannelId) {
if (isTalkingRef.current) {
setTalking({ talking: false });
setTalking({ talking: false, channelId: connectedChannelId || 0n });
isTalkingRef.current = false;
setIsTalking(false);
}
@@ -122,14 +122,14 @@ export const useLocalMedia = () => {
if (average > threshold) {
silenceFrames = 0;
if (!isTalkingRef.current) {
setTalking({ talking: true });
setTalking({ talking: true, channelId: connectedChannelId });
isTalkingRef.current = true;
setIsTalking(true);
}
} else {
silenceFrames++;
if (silenceFrames > maxSilenceFrames && isTalkingRef.current) {
setTalking({ talking: false });
setTalking({ talking: false, channelId: connectedChannelId });
isTalkingRef.current = false;
setIsTalking(false);
}
@@ -140,7 +140,7 @@ export const useLocalMedia = () => {
clearInterval(checkAudio);
audioContext.close();
};
}, [localStream, setTalking, isMuted, isDeafened]);
}, [localStream, setTalking, isMuted, isDeafened, connectedChannelId]);
return {
localStream,
@@ -1,18 +1,42 @@
import { useEffect, useCallback, useMemo, useRef } from "react";
import { Identity } from "spacetimedb";
import { useTable, useReducer } from "spacetimedb/react";
import { useTable, useReducer, useSpacetimeDB } from "spacetimedb/react";
import { tables, reducers } from "../../../module_bindings";
import { usePeerManager } from "./usePeerManager";
export const useScreenSharingWebRTC = (
connectedChannelId: bigint | undefined,
identity: Identity | null,
localScreenStream: MediaStream | null,
) => {
const { identity } = useSpacetimeDB();
const [watching] = useTable(tables.watching);
const [offers] = useTable(tables.screen_sdp_offer);
const [answers] = useTable(tables.screen_sdp_answer);
const [iceCandidates] = useTable(tables.screen_ice_candidate);
const [offers] = useTable(
useMemo(
() =>
identity
? tables.screen_sdp_offer.where((o) => o.receiver.eq(identity))
: tables.screen_sdp_offer.where(() => false),
[identity],
),
);
const [answers] = useTable(
useMemo(
() =>
identity
? tables.screen_sdp_answer.where((o) => o.receiver.eq(identity))
: tables.screen_sdp_answer.where(() => false),
[identity],
),
);
const [iceCandidates] = useTable(
useMemo(
() =>
identity
? tables.screen_ice_candidate.where((o) => o.receiver.eq(identity))
: tables.screen_ice_candidate.where(() => false),
[identity],
),
);
const sendSdpOffer = useReducer(reducers.sendScreenSdpOffer);
const sendSdpAnswer = useReducer(reducers.sendScreenSdpAnswer);
@@ -121,7 +145,7 @@ export const useScreenSharingWebRTC = (
);
const peerManager = usePeerManager(
identity,
identity || null,
"screen",
false,
onNegotiationNeeded,
+2 -3
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect } from "react";
import { useCallback, useEffect, useMemo } from "react";
import { Identity } from "spacetimedb";
import { useTable, useReducer, useSpacetimeDB } from "spacetimedb/react";
import { tables, reducers } from "../../../module_bindings";
@@ -27,7 +27,7 @@ export const useWebRTC = (connectedChannelId: bigint | undefined) => {
stopScreenShare: stopLocalScreenShare,
requestMic,
releaseMic,
} = useLocalMedia();
} = useLocalMedia(connectedChannelId);
// Sync mute/deafen to DB
useEffect(() => {
@@ -52,7 +52,6 @@ export const useWebRTC = (connectedChannelId: bigint | undefined) => {
const screen = useScreenSharingWebRTC(
connectedChannelId,
identity || null,
localScreenStream,
);
+4 -1
View File
@@ -9,7 +9,10 @@ import {
type AlgebraicTypeType as __AlgebraicTypeType,
type Infer as __Infer,
} from "spacetimedb";
import { ChannelKind } from "./types";
import {
ChannelKind,
} from "./types";
export default __t.row({
id: __t.u64().primaryKey(),
+265 -448
View File
@@ -81,434 +81,262 @@ import WatchingRow from "./watching_table";
/** The schema information for all tables in this module. This is defined the same was as the tables would have been defined in the server. */
const tablesSchema = __schema({
channel: __table(
{
name: "channel",
indexes: [
{
accessor: "id",
name: "channel_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_server_id",
name: "channel_server_id_idx_btree",
algorithm: "btree",
columns: ["serverId"],
},
],
constraints: [
{ name: "channel_id_key", constraint: "unique", columns: ["id"] },
],
},
ChannelRow,
),
message: __table(
{
name: "message",
indexes: [
{
accessor: "by_channel_id",
name: "message_channel_id_idx_btree",
algorithm: "btree",
columns: ["channelId"],
},
{
accessor: "id",
name: "message_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_thread_id",
name: "message_thread_id_idx_btree",
algorithm: "btree",
columns: ["threadId"],
},
],
constraints: [
{ name: "message_id_key", constraint: "unique", columns: ["id"] },
],
},
MessageRow,
),
screen_ice_candidate: __table(
{
name: "screen_ice_candidate",
indexes: [
{
accessor: "id",
name: "screen_ice_candidate_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "screen_ice_candidate_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "screen_ice_candidate_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "screen_ice_candidate_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
ScreenIceCandidateRow,
),
screen_sdp_answer: __table(
{
name: "screen_sdp_answer",
indexes: [
{
accessor: "id",
name: "screen_sdp_answer_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "screen_sdp_answer_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "screen_sdp_answer_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "screen_sdp_answer_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
ScreenSdpAnswerRow,
),
screen_sdp_offer: __table(
{
name: "screen_sdp_offer",
indexes: [
{
accessor: "id",
name: "screen_sdp_offer_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "screen_sdp_offer_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "screen_sdp_offer_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "screen_sdp_offer_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
ScreenSdpOfferRow,
),
server: __table(
{
name: "server",
indexes: [
{
accessor: "id",
name: "server_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
],
constraints: [
{ name: "server_id_key", constraint: "unique", columns: ["id"] },
],
},
ServerRow,
),
server_member: __table(
{
name: "server_member",
indexes: [
{
accessor: "id",
name: "server_member_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_identity",
name: "server_member_identity_idx_btree",
algorithm: "btree",
columns: ["identity"],
},
{
accessor: "by_server_id",
name: "server_member_server_id_idx_btree",
algorithm: "btree",
columns: ["serverId"],
},
],
constraints: [
{ name: "server_member_id_key", constraint: "unique", columns: ["id"] },
],
},
ServerMemberRow,
),
thread: __table(
{
name: "thread",
indexes: [
{
accessor: "by_channel_id",
name: "thread_channel_id_idx_btree",
algorithm: "btree",
columns: ["channelId"],
},
{
accessor: "id",
name: "thread_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "parent_message_id",
name: "thread_parent_message_id_idx_btree",
algorithm: "btree",
columns: ["parentMessageId"],
},
],
constraints: [
{ name: "thread_id_key", constraint: "unique", columns: ["id"] },
{
name: "thread_parent_message_id_key",
constraint: "unique",
columns: ["parentMessageId"],
},
],
},
ThreadRow,
),
user: __table(
{
name: "user",
indexes: [
{
accessor: "identity",
name: "user_identity_idx_btree",
algorithm: "btree",
columns: ["identity"],
},
],
constraints: [
{
name: "user_identity_key",
constraint: "unique",
columns: ["identity"],
},
],
},
UserRow,
),
voice_activity: __table(
{
name: "voice_activity",
indexes: [
{
accessor: "identity",
name: "voice_activity_identity_idx_btree",
algorithm: "btree",
columns: ["identity"],
},
],
constraints: [
{
name: "voice_activity_identity_key",
constraint: "unique",
columns: ["identity"],
},
],
},
VoiceActivityRow,
),
voice_ice_candidate: __table(
{
name: "voice_ice_candidate",
indexes: [
{
accessor: "id",
name: "voice_ice_candidate_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "voice_ice_candidate_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "voice_ice_candidate_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "voice_ice_candidate_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
VoiceIceCandidateRow,
),
voice_sdp_answer: __table(
{
name: "voice_sdp_answer",
indexes: [
{
accessor: "id",
name: "voice_sdp_answer_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "voice_sdp_answer_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "voice_sdp_answer_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "voice_sdp_answer_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
VoiceSdpAnswerRow,
),
voice_sdp_offer: __table(
{
name: "voice_sdp_offer",
indexes: [
{
accessor: "id",
name: "voice_sdp_offer_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_receiver",
name: "voice_sdp_offer_receiver_idx_btree",
algorithm: "btree",
columns: ["receiver"],
},
{
accessor: "by_sender",
name: "voice_sdp_offer_sender_idx_btree",
algorithm: "btree",
columns: ["sender"],
},
],
constraints: [
{
name: "voice_sdp_offer_id_key",
constraint: "unique",
columns: ["id"],
},
],
},
VoiceSdpOfferRow,
),
voice_state: __table(
{
name: "voice_state",
indexes: [
{
accessor: "by_channel_id",
name: "voice_state_channel_id_idx_btree",
algorithm: "btree",
columns: ["channelId"],
},
{
accessor: "identity",
name: "voice_state_identity_idx_btree",
algorithm: "btree",
columns: ["identity"],
},
],
constraints: [
{
name: "voice_state_identity_key",
constraint: "unique",
columns: ["identity"],
},
],
},
VoiceStateRow,
),
watching: __table(
{
name: "watching",
indexes: [
{
accessor: "id",
name: "watching_id_idx_btree",
algorithm: "btree",
columns: ["id"],
},
{
accessor: "by_watchee",
name: "watching_watchee_idx_btree",
algorithm: "btree",
columns: ["watchee"],
},
{
accessor: "by_watcher",
name: "watching_watcher_idx_btree",
algorithm: "btree",
columns: ["watcher"],
},
],
constraints: [
{ name: "watching_id_key", constraint: "unique", columns: ["id"] },
],
},
WatchingRow,
),
channel: __table({
name: 'channel',
indexes: [
{ accessor: 'id', name: 'channel_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_server_id', name: 'channel_server_id_idx_btree', algorithm: 'btree', columns: [
'serverId',
] },
],
constraints: [
{ name: 'channel_id_key', constraint: 'unique', columns: ['id'] },
],
}, ChannelRow),
message: __table({
name: 'message',
indexes: [
{ accessor: 'by_channel_id', name: 'message_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'message_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_thread_id', name: 'message_thread_id_idx_btree', algorithm: 'btree', columns: [
'threadId',
] },
],
constraints: [
{ name: 'message_id_key', constraint: 'unique', columns: ['id'] },
],
}, MessageRow),
screen_ice_candidate: __table({
name: 'screen_ice_candidate',
indexes: [
{ accessor: 'by_channel_id', name: 'screen_ice_candidate_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'screen_ice_candidate_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'screen_ice_candidate_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'screen_ice_candidate_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'screen_ice_candidate_id_key', constraint: 'unique', columns: ['id'] },
],
}, ScreenIceCandidateRow),
screen_sdp_answer: __table({
name: 'screen_sdp_answer',
indexes: [
{ accessor: 'by_channel_id', name: 'screen_sdp_answer_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'screen_sdp_answer_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'screen_sdp_answer_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'screen_sdp_answer_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'screen_sdp_answer_id_key', constraint: 'unique', columns: ['id'] },
],
}, ScreenSdpAnswerRow),
screen_sdp_offer: __table({
name: 'screen_sdp_offer',
indexes: [
{ accessor: 'by_channel_id', name: 'screen_sdp_offer_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'screen_sdp_offer_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'screen_sdp_offer_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'screen_sdp_offer_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'screen_sdp_offer_id_key', constraint: 'unique', columns: ['id'] },
],
}, ScreenSdpOfferRow),
server: __table({
name: 'server',
indexes: [
{ accessor: 'id', name: 'server_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
],
constraints: [
{ name: 'server_id_key', constraint: 'unique', columns: ['id'] },
],
}, ServerRow),
server_member: __table({
name: 'server_member',
indexes: [
{ accessor: 'id', name: 'server_member_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_identity', name: 'server_member_identity_idx_btree', algorithm: 'btree', columns: [
'identity',
] },
{ accessor: 'by_server_id', name: 'server_member_server_id_idx_btree', algorithm: 'btree', columns: [
'serverId',
] },
],
constraints: [
{ name: 'server_member_id_key', constraint: 'unique', columns: ['id'] },
],
}, ServerMemberRow),
thread: __table({
name: 'thread',
indexes: [
{ accessor: 'by_channel_id', name: 'thread_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'thread_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'parent_message_id', name: 'thread_parent_message_id_idx_btree', algorithm: 'btree', columns: [
'parentMessageId',
] },
],
constraints: [
{ name: 'thread_id_key', constraint: 'unique', columns: ['id'] },
{ name: 'thread_parent_message_id_key', constraint: 'unique', columns: ['parentMessageId'] },
],
}, ThreadRow),
user: __table({
name: 'user',
indexes: [
{ accessor: 'identity', name: 'user_identity_idx_btree', algorithm: 'btree', columns: [
'identity',
] },
],
constraints: [
{ name: 'user_identity_key', constraint: 'unique', columns: ['identity'] },
],
}, UserRow),
voice_activity: __table({
name: 'voice_activity',
indexes: [
{ accessor: 'by_channel_id', name: 'voice_activity_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'identity', name: 'voice_activity_identity_idx_btree', algorithm: 'btree', columns: [
'identity',
] },
],
constraints: [
{ name: 'voice_activity_identity_key', constraint: 'unique', columns: ['identity'] },
],
}, VoiceActivityRow),
voice_ice_candidate: __table({
name: 'voice_ice_candidate',
indexes: [
{ accessor: 'by_channel_id', name: 'voice_ice_candidate_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'voice_ice_candidate_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'voice_ice_candidate_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'voice_ice_candidate_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'voice_ice_candidate_id_key', constraint: 'unique', columns: ['id'] },
],
}, VoiceIceCandidateRow),
voice_sdp_answer: __table({
name: 'voice_sdp_answer',
indexes: [
{ accessor: 'by_channel_id', name: 'voice_sdp_answer_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'voice_sdp_answer_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'voice_sdp_answer_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'voice_sdp_answer_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'voice_sdp_answer_id_key', constraint: 'unique', columns: ['id'] },
],
}, VoiceSdpAnswerRow),
voice_sdp_offer: __table({
name: 'voice_sdp_offer',
indexes: [
{ accessor: 'by_channel_id', name: 'voice_sdp_offer_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'voice_sdp_offer_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_receiver', name: 'voice_sdp_offer_receiver_idx_btree', algorithm: 'btree', columns: [
'receiver',
] },
{ accessor: 'by_sender', name: 'voice_sdp_offer_sender_idx_btree', algorithm: 'btree', columns: [
'sender',
] },
],
constraints: [
{ name: 'voice_sdp_offer_id_key', constraint: 'unique', columns: ['id'] },
],
}, VoiceSdpOfferRow),
voice_state: __table({
name: 'voice_state',
indexes: [
{ accessor: 'by_channel_id', name: 'voice_state_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'identity', name: 'voice_state_identity_idx_btree', algorithm: 'btree', columns: [
'identity',
] },
],
constraints: [
{ name: 'voice_state_identity_key', constraint: 'unique', columns: ['identity'] },
],
}, VoiceStateRow),
watching: __table({
name: 'watching',
indexes: [
{ accessor: 'by_channel_id', name: 'watching_channel_id_idx_btree', algorithm: 'btree', columns: [
'channelId',
] },
{ accessor: 'id', name: 'watching_id_idx_btree', algorithm: 'btree', columns: [
'id',
] },
{ accessor: 'by_watchee', name: 'watching_watchee_idx_btree', algorithm: 'btree', columns: [
'watchee',
] },
{ accessor: 'by_watcher', name: 'watching_watcher_idx_btree', algorithm: 'btree', columns: [
'watcher',
] },
],
constraints: [
{ name: 'watching_id_key', constraint: 'unique', columns: ['id'] },
],
}, WatchingRow),
});
/** The schema information for all reducers in this module. This is defined the same way as the reducers would have been defined in the server, except the body of the reducer is omitted in code generation. */
@@ -539,7 +367,8 @@ const reducersSchema = __reducers(
);
/** The schema information for all procedures in this module. This is defined the same way as the procedures would have been defined in the server. */
const proceduresSchema = __procedures();
const proceduresSchema = __procedures(
);
/** The remote SpacetimeDB module schema, both runtime and type information. */
const REMOTE_MODULE = {
@@ -556,33 +385,24 @@ const REMOTE_MODULE = {
>;
/** The tables available in this remote SpacetimeDB module. Each table reference doubles as a query builder. */
export const tables: __QueryBuilder<typeof tablesSchema.schemaType> =
__makeQueryBuilder(tablesSchema.schemaType);
export const tables: __QueryBuilder<typeof tablesSchema.schemaType> = __makeQueryBuilder(tablesSchema.schemaType);
/** The reducers available in this remote SpacetimeDB module. */
export const reducers = __convertToAccessorMap(
reducersSchema.reducersType.reducers,
);
export const reducers = __convertToAccessorMap(reducersSchema.reducersType.reducers);
/** The context type returned in callbacks for all possible events. */
export type EventContext = __EventContextInterface<typeof REMOTE_MODULE>;
/** The context type returned in callbacks for reducer events. */
export type ReducerEventContext = __ReducerEventContextInterface<
typeof REMOTE_MODULE
>;
export type ReducerEventContext = __ReducerEventContextInterface<typeof REMOTE_MODULE>;
/** The context type returned in callbacks for subscription events. */
export type SubscriptionEventContext = __SubscriptionEventContextInterface<
typeof REMOTE_MODULE
>;
export type SubscriptionEventContext = __SubscriptionEventContextInterface<typeof REMOTE_MODULE>;
/** The context type returned in callbacks for error events. */
export type ErrorContext = __ErrorContextInterface<typeof REMOTE_MODULE>;
/** The subscription handle type to manage active subscriptions created from a {@link SubscriptionBuilder}. */
export type SubscriptionHandle = __SubscriptionHandleImpl<typeof REMOTE_MODULE>;
/** Builder class to configure a new subscription to the remote SpacetimeDB instance. */
export class SubscriptionBuilder extends __SubscriptionBuilderImpl<
typeof REMOTE_MODULE
> {}
export class SubscriptionBuilder extends __SubscriptionBuilderImpl<typeof REMOTE_MODULE> {}
/** Builder class to configure a new database connection to the remote SpacetimeDB instance. */
export class DbConnectionBuilder extends __DbConnectionBuilder<DbConnection> {}
@@ -591,11 +411,7 @@ export class DbConnectionBuilder extends __DbConnectionBuilder<DbConnection> {}
export class DbConnection extends __DbConnectionImpl<typeof REMOTE_MODULE> {
/** Creates a new {@link DbConnectionBuilder} to configure and connect to the remote SpacetimeDB instance. */
static builder = (): DbConnectionBuilder => {
return new DbConnectionBuilder(
REMOTE_MODULE,
(config: __DbConnectionConfig<typeof REMOTE_MODULE>) =>
new DbConnection(config),
);
return new DbConnectionBuilder(REMOTE_MODULE, (config: __DbConnectionConfig<typeof REMOTE_MODULE>) => new DbConnection(config));
};
/** Creates a new {@link SubscriptionBuilder} to configure a subscription to the remote SpacetimeDB instance. */
@@ -603,3 +419,4 @@ export class DbConnection extends __DbConnectionImpl<typeof REMOTE_MODULE> {
return new SubscriptionBuilder(this);
};
}
+1
View File
@@ -12,4 +12,5 @@ import {
export default {
talking: __t.bool(),
channelId: __t.u64(),
};
+2
View File
@@ -99,6 +99,7 @@ export type User = __Infer<typeof User>;
export const VoiceActivity = __t.object("VoiceActivity", {
identity: __t.identity(),
channelId: __t.u64(),
isTalking: __t.bool(),
});
export type VoiceActivity = __Infer<typeof VoiceActivity>;
@@ -146,3 +147,4 @@ export const Watching = __t.object("Watching", {
channelId: __t.u64(),
});
export type Watching = __Infer<typeof Watching>;
+2
View File
@@ -6,3 +6,5 @@
import { type Infer as __Infer } from "spacetimedb";
// Import all procedure arg schemas
+6 -15
View File
@@ -40,21 +40,11 @@ export type LeaveVoiceParams = __Infer<typeof LeaveVoiceReducer>;
export type LoginParams = __Infer<typeof LoginReducer>;
export type RegisterParams = __Infer<typeof RegisterReducer>;
export type SendMessageParams = __Infer<typeof SendMessageReducer>;
export type SendScreenIceCandidateParams = __Infer<
typeof SendScreenIceCandidateReducer
>;
export type SendScreenSdpAnswerParams = __Infer<
typeof SendScreenSdpAnswerReducer
>;
export type SendScreenSdpOfferParams = __Infer<
typeof SendScreenSdpOfferReducer
>;
export type SendVoiceIceCandidateParams = __Infer<
typeof SendVoiceIceCandidateReducer
>;
export type SendVoiceSdpAnswerParams = __Infer<
typeof SendVoiceSdpAnswerReducer
>;
export type SendScreenIceCandidateParams = __Infer<typeof SendScreenIceCandidateReducer>;
export type SendScreenSdpAnswerParams = __Infer<typeof SendScreenSdpAnswerReducer>;
export type SendScreenSdpOfferParams = __Infer<typeof SendScreenSdpOfferReducer>;
export type SendVoiceIceCandidateParams = __Infer<typeof SendVoiceIceCandidateReducer>;
export type SendVoiceSdpAnswerParams = __Infer<typeof SendVoiceSdpAnswerReducer>;
export type SendVoiceSdpOfferParams = __Infer<typeof SendVoiceSdpOfferReducer>;
export type SetDeafenParams = __Infer<typeof SetDeafenReducer>;
export type SetMuteParams = __Infer<typeof SetMuteReducer>;
@@ -63,3 +53,4 @@ export type SetSharingScreenParams = __Infer<typeof SetSharingScreenReducer>;
export type SetTalkingParams = __Infer<typeof SetTalkingReducer>;
export type StartWatchingParams = __Infer<typeof StartWatchingReducer>;
export type StopWatchingParams = __Infer<typeof StopWatchingReducer>;
+1
View File
@@ -12,5 +12,6 @@ import {
export default __t.row({
identity: __t.identity().primaryKey(),
channelId: __t.u64().name("channel_id"),
isTalking: __t.bool().name("is_talking"),
});