TTP -> MTP, A lot of other stuff #21

Merged
alois merged 81 commits from dev into main 2026-07-21 11:57:33 +03:00
23 changed files with 214 additions and 248 deletions
Showing only changes of commit 7f75a36d73 - Show all commits

(wip): migrate ttp to mtp -> snake case to pascal case
Some checks failed
/ build-web (push) Successful in 6m13s
/ build-desktop (linux) (push) Successful in 7m1s
/ build-mobile (push) Failing after 9m20s
/ release (push) Has been skipped

Alois 2026-07-03 11:08:38 +02:00

View file

@ -34,7 +34,7 @@ export function Basic({
<div className="absolute -bottom-0.5 -right-0.5 z-10 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-card"> <div className="absolute -bottom-0.5 -right-0.5 z-10 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-card">
<div <div
style={{ style={{
backgroundColor: getStatusColor(user.online_status), backgroundColor: getStatusColor(user.OnlineStatus),
}} }}
className="h-2.25 w-2.25 rounded-full" className="h-2.25 w-2.25 rounded-full"
/> />
@ -42,8 +42,7 @@ export function Basic({
} }
/> />
<TooltipContent> <TooltipContent>
{user.online_status {user.OnlineStatus.split("_")
.split("_")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ")} .join(" ")}
</TooltipContent> </TooltipContent>

View file

@ -34,8 +34,8 @@ export default function Profile({ user }: { user: User }) {
const ownData = await get(ownId); const ownData = await get(ownId);
const secret = await getSharedSecret( const secret = await getSharedSecret(
privateKey, privateKey,
ownData.public_key, ownData.PublicKey,
user.public_key, user.PublicKey,
); );
if (active) { if (active) {
@ -51,7 +51,7 @@ export default function Profile({ user }: { user: User }) {
return () => { return () => {
active = false; active = false;
}; };
}, [get, getSharedSecret, load, user.public_key]); }, [get, getSharedSecret, load, user.PublicKey]);
const sharedSecretCode = sharedSecret const sharedSecretCode = sharedSecret
? toLossySixDigitCode(sharedSecret) ? toLossySixDigitCode(sharedSecret)
@ -98,13 +98,13 @@ export default function Profile({ user }: { user: User }) {
</Tooltip> </Tooltip>
</p> </p>
<p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap"> <p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap">
Iota ID: <code>{user.iota_id}</code> Iota ID: <code>{user.IotaId}</code>
</p> </p>
<p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap"> <p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap">
User ID: <code>{user.user_id}</code> User ID: <code>{user.UserId}</code>
</p> </p>
<p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap"> <p className="text-muted-foreground text-xs overflow-hidden text-ellipsis whitespace-nowrap">
Public Key: <code>{user.public_key}</code> Public Key: <code>{user.PublicKey}</code>
</p> </p>
</div> </div>
)} )}

View file

@ -28,7 +28,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
const { id } = useSearch({ strict: false }); const { id } = useSearch({ strict: false });
const currentCalls = calls.filter((call) => const currentCalls = calls.filter((call) =>
call.call_members.some((member) => member === id), call.CallMembers.some((member) => member === id),
); );
const isMobile = useIsMobile(); const isMobile = useIsMobile();
@ -121,8 +121,8 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
onClick={() => { onClick={() => {
void joinCall( void joinCall(
id, id,
currentCalls[0].call_secret, currentCalls[0].CallSecret,
currentCalls[0].call_id, currentCalls[0].CallId,
); );
}} }}
className="w-9 h-9 aspect-square rounded-lg" className="w-9 h-9 aspect-square rounded-lg"
@ -147,13 +147,13 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
<SelectContent className="p-1"> <SelectContent className="p-1">
{currentCalls.map((call) => ( {currentCalls.map((call) => (
<SelectItem <SelectItem
value={call.call_id} value={call.CallId}
key={call.call_id} key={call.CallId}
onSelect={() => { onSelect={() => {
void joinCall(id, call.call_secret, call.call_id); void joinCall(id, call.CallSecret, call.CallId);
}} }}
> >
{displayCallId(call.call_id)} {displayCallId(call.CallId)}
</SelectItem> </SelectItem>
))} ))}
</SelectContent> </SelectContent>

View file

@ -41,7 +41,7 @@ import { mtp } from "@tensamin/shared/data";
import { useMTP } from "@tensamin/mtp"; import { useMTP } from "@tensamin/mtp";
type OnlineStatus = z.infer< type OnlineStatus = z.infer<
typeof mtp.get_user_data.response.shape.online_status typeof mtp.get_user_data.response.shape.OnlineStatus
>; >;
const onlineStatusLabels: Record<OnlineStatus, string> = { const onlineStatusLabels: Record<OnlineStatus, string> = {
@ -89,7 +89,7 @@ function StatusDialog({
onOpenChange={(nextOpen) => { onOpenChange={(nextOpen) => {
if (!nextOpen) { if (!nextOpen) {
setDraftStatus(user.status ?? ""); setDraftStatus(user.status ?? "");
setDraftOnlineStatus(user.online_status); setDraftOnlineStatus(user.OnlineStatus);
setErrorMessage(""); setErrorMessage("");
setSaveSucceeded(false); setSaveSucceeded(false);
} }
@ -144,7 +144,7 @@ function StatusDialog({
onClick={async () => { onClick={async () => {
const payload = { const payload = {
...(draftStatus && { status: draftStatus }), ...(draftStatus && { status: draftStatus }),
online_status: draftOnlineStatus, OnlineStatus: draftOnlineStatus,
}; };
const validation = const validation =
@ -230,7 +230,7 @@ export default function Sidebar() {
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
setDraftStatus(user.status ?? ""); setDraftStatus(user.status ?? "");
setDraftOnlineStatus(user.online_status); setDraftOnlineStatus(user.OnlineStatus);
setStatusErrorMessage(""); setStatusErrorMessage("");
setStatusSaveSucceeded(false); setStatusSaveSucceeded(false);
setDialogOpen(true); setDialogOpen(true);
@ -249,7 +249,7 @@ export default function Sidebar() {
onOpenChange={(nextOpen) => { onOpenChange={(nextOpen) => {
if (!nextOpen) { if (!nextOpen) {
setDraftStatus(user.status ?? ""); setDraftStatus(user.status ?? "");
setDraftOnlineStatus(user.online_status); setDraftOnlineStatus(user.OnlineStatus);
setStatusErrorMessage(""); setStatusErrorMessage("");
setStatusSaveSucceeded(false); setStatusSaveSucceeded(false);
} }

View file

@ -65,7 +65,7 @@ export default function List() {
{category === "conversations" ? ( {category === "conversations" ? (
contacts?.[virtualItem.index] ? ( contacts?.[virtualItem.index] ? (
<ConversationModal <ConversationModal
userId={contacts[virtualItem.index].user_id} userId={contacts[virtualItem.index].UserId}
/> />
) : null ) : null
) : communities?.[virtualItem.index] ? ( ) : communities?.[virtualItem.index] ? (

View file

@ -59,7 +59,7 @@ function AddConversationButton() {
username: result.data, username: result.data,
}) })
.then((data) => { .then((data) => {
if (data.data.user_id === 0) { if (data.data.UserId === 0) {
throw new Error(); throw new Error();
} }
@ -72,7 +72,7 @@ function AddConversationButton() {
if (!user) return; if (!user) return;
// alrady added check // alrady added check
if (contacts.some((contact) => contact.user_id === user.data.user_id)) { if (contacts.some((contact) => contact.UserId === user.data.UserId)) {
setError("Conversation already exists"); setError("Conversation already exists");
return; return;
} }
@ -81,10 +81,10 @@ function AddConversationButton() {
const timeout = setTimeout(() => setLoading(true), 500); const timeout = setTimeout(() => setLoading(true), 500);
send("add_conversation", { send("add_conversation", {
chat_partner_name: result.data, ChatPartnerName: result.data,
}) })
.then(() => { .then(() => {
insertContact(user.data.user_id); insertContact(user.data.UserId);
setOpen(false); setOpen(false);
}) })
.catch((error) => { .catch((error) => {

View file

@ -61,15 +61,15 @@ export default function InviteButton({
> >
{contacts.map((contact) => ( {contacts.map((contact) => (
<Wrapper <Wrapper
key={contact.user_id} key={contact.UserId}
userId={contact.user_id} userId={contact.UserId}
loading={<div>Loading...</div>} loading={<div>Loading...</div>}
component={(user) => ( component={(user) => (
<Button <Button
className="w-full justify-start" className="w-full justify-start"
variant="ghost" variant="ghost"
onClick={() => { onClick={() => {
void sendCallInvite(contact.user_id).catch((err) => { void sendCallInvite(contact.UserId).catch((err) => {
toast( toast(
"error", "error",
"Failed to send call invite. Check console for details.", "Failed to send call invite. Check console for details.",

View file

@ -115,7 +115,7 @@ function Overlay({
user: User; user: User;
participant: Participant; participant: Participant;
}) { }) {
const isAdmin = getRoomMetadata()?.admins.includes(user.user_id) === true; const isAdmin = getRoomMetadata()?.admins.includes(user.UserId) === true;
const isDeafened = participant.attributes["deafened"] === "true"; const isDeafened = participant.attributes["deafened"] === "true";
return ( return (
@ -171,7 +171,7 @@ export default function Base({
const [avatarBackgroundColor, setAvatarBackgroundColor] = useState< const [avatarBackgroundColor, setAvatarBackgroundColor] = useState<
string | undefined string | undefined
>(undefined); >(undefined);
const isSpeaking = useIsSpeaking(user?.user_id ?? -1); const isSpeaking = useIsSpeaking(user?.UserId ?? -1);
const screenSharePublication = getTrackPublicationBySource( const screenSharePublication = getTrackPublicationBySource(
participant, participant,
Track.Source.ScreenShare, Track.Source.ScreenShare,
@ -242,12 +242,12 @@ export default function Base({
const onClick = () => { const onClick = () => {
if (view === "grid") { if (view === "grid") {
focusParticipant(user.user_id, type); focusParticipant(user.UserId, type);
} else { } else {
if (user.user_id === focusedParticipantId) { if (user.UserId === focusedParticipantId) {
setCallView("grid"); setCallView("grid");
} else { } else {
focusParticipant(user.user_id, type); focusParticipant(user.UserId, type);
} }
} }
}; };
@ -256,7 +256,7 @@ export default function Base({
screenSharePublication?.isSubscribed && screenSharePublication.track; screenSharePublication?.isSubscribed && screenSharePublication.track;
const isFocusedInFocusedView = const isFocusedInFocusedView =
view === "focused" && user.user_id === focusedParticipantId; view === "focused" && user.UserId === focusedParticipantId;
return ( return (
<UIContextMenu> <UIContextMenu>
@ -276,7 +276,7 @@ export default function Base({
variant="outline" variant="outline"
onClick={(event) => { onClick={(event) => {
if (isFocusedInFocusedView) event.stopPropagation(); if (isFocusedInFocusedView) event.stopPropagation();
startWatchingStream(user.user_id); startWatchingStream(user.UserId);
}} }}
> >
Watch Stream Watch Stream
@ -286,7 +286,7 @@ export default function Base({
variant="outline" variant="outline"
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
startWatchingStream(user.user_id); startWatchingStream(user.UserId);
}} }}
> >
<Plus className="w-8 h-8" /> <Plus className="w-8 h-8" />
@ -295,8 +295,7 @@ export default function Base({
</div> </div>
)} )}
{view === "grid" || {view === "grid" ||
(view === "focused" && (view === "focused" && user.UserId !== focusedParticipantId) ? (
user.user_id !== focusedParticipantId) ? (
<Overlay type={type} user={user} participant={participant} /> <Overlay type={type} user={user} participant={participant} />
) : null} ) : null}
</> </>

View file

@ -36,8 +36,8 @@ export default function ContextMenu({
return ( return (
<ContextMenuContent className="p-1"> <ContextMenuContent className="p-1">
{watchedStreamParticipantIds.includes(user.user_id) && {watchedStreamParticipantIds.includes(user.UserId) &&
user.user_id !== ownId ? ( user.UserId !== ownId ? (
<ContextMenuItem variant="destructive">Stop Watching</ContextMenuItem> <ContextMenuItem variant="destructive">Stop Watching</ContextMenuItem>
) : null} ) : null}
<ContextMenuItem>Profile</ContextMenuItem> <ContextMenuItem>Profile</ContextMenuItem>

View file

@ -70,7 +70,7 @@ export default function TopBar() {
<div className="w-full flex justify-between h-12"> <div className="w-full flex justify-between h-12">
<div className="flex gap-1 m-3 ml-7"> <div className="flex gap-1 m-3 ml-7">
{users.map((user) => ( {users.map((user) => (
<div key={user.user_id} className="-ml-4"> <div key={user.UserId} className="-ml-4">
<Tooltip> <Tooltip>
<TooltipTrigger <TooltipTrigger
render={ render={

View file

@ -70,7 +70,7 @@ type GetSharedSecretFn = (
type DecryptTextFn = (sharedSecret: string, text: string) => Promise<string>; type DecryptTextFn = (sharedSecret: string, text: string) => Promise<string>;
type EncryptTextFn = (sharedSecret: string, text: string) => Promise<string>; type EncryptTextFn = (sharedSecret: string, text: string) => Promise<string>;
type LoadFn = (key: string) => Promise<unknown>; type LoadFn = (key: string) => Promise<unknown>;
type GetUserFn = (userId: number) => Promise<{ public_key: string }>; type GetUserFn = (userId: number) => Promise<{ PublicKey: string }>;
type RemoteVideoTrackSelector = Track.Kind | Track.Source; type RemoteVideoTrackSelector = Track.Kind | Track.Source;
type Runtime = { type Runtime = {
@ -605,15 +605,15 @@ export async function openCallPage(callId: string) {
export async function getCallToken(callId: string): Promise<string> { export async function getCallToken(callId: string): Promise<string> {
const response = await requireRuntime(useCall.getState().runtime) const response = await requireRuntime(useCall.getState().runtime)
.send("call_token", { .send("call_token", {
call_id: callId, CallId: callId,
}) })
.catch((err) => { .catch((err) => {
log(1, "call", "red", "Failed to get call secret", err); log(1, "call", "red", "Failed to get call secret", err);
throw err; throw err;
}); });
const data = response.data as { call_token: string }; const data = response.data as { CallToken: string };
return data.call_token; return data.CallToken;
} }
// Encrypt the active call secret for a recipient and send the call invite. // Encrypt the active call secret for a recipient and send the call invite.
@ -629,10 +629,10 @@ export async function sendCallInvite(userId: number) {
const privateKey = await runtime.load("private_key"); const privateKey = await runtime.load("private_key");
const ownPublicKey = await runtime const ownPublicKey = await runtime
.getUser(ownUserId) .getUser(ownUserId)
.then((data) => data.public_key); .then((data) => data.PublicKey);
const remotePublicKey = await runtime const remotePublicKey = await runtime
.getUser(userId) .getUser(userId)
.then((data) => data.public_key); .then((data) => data.PublicKey);
const sharedSecret = await runtime.getSharedSecret( const sharedSecret = await runtime.getSharedSecret(
privateKey, privateKey,
ownPublicKey, ownPublicKey,
@ -644,9 +644,9 @@ export async function sendCallInvite(userId: number) {
); );
await runtime.send("call_invite", { await runtime.send("call_invite", {
receiver_id: userId, ReceiverId: userId,
call_id: callId, CallId: callId,
call_secret: encryptedCallSecret, CallSecret: encryptedCallSecret,
}); });
} }
@ -900,8 +900,8 @@ export async function joinCall(
await runtime.load("private_key"), await runtime.load("private_key"),
await runtime await runtime
.getUser((await runtime.load("user_id")) as number) .getUser((await runtime.load("user_id")) as number)
.then((res) => res.public_key), .then((res) => res.PublicKey),
await runtime.getUser(userId).then((res) => res.public_key), await runtime.getUser(userId).then((res) => res.PublicKey),
); );
const decryptedSecret = await runtime.decryptText( const decryptedSecret = await runtime.decryptText(
sharedSecret, sharedSecret,
@ -1150,9 +1150,9 @@ export function useInitializeCall() {
} }
insertCall({ insertCall({
call_id: invite.callId, CallId: invite.callId,
call_secret: invite.callSecret, CallSecret: invite.callSecret,
call_members: [invite.senderId], CallMembers: [invite.senderId],
}); });
if (accepted) { if (accepted) {
@ -1180,13 +1180,13 @@ export function useInitializeCall() {
subscribePush(async (message) => { subscribePush(async (message) => {
if (message.type !== "call_invite") return; if (message.type !== "call_invite") return;
const { call_id, call_secret, sender_id } = message.data as { const { CallId, CallSecret, SenderId } = message.data as {
call_id: string; CallId: string;
call_secret: string; CallSecret: string;
sender_id: number; SenderId: number;
}; };
showCallingScreen(call_id, call_secret, sender_id); showCallingScreen(CallId, CallSecret, SenderId);
}); });
}, [subscribePush, showCallingScreen]); }, [subscribePush, showCallingScreen]);
@ -1500,7 +1500,7 @@ export function useInitializeCall() {
return; return;
} }
send("call_data", { call_id: callId }) send("call_data", { CallId: callId })
.then((data) => { .then((data) => {
setCurrentCallData({ setCurrentCallData({
...(data.data as z.infer<typeof mtp.call_data.response>), ...(data.data as z.infer<typeof mtp.call_data.response>),
@ -1513,7 +1513,7 @@ export function useInitializeCall() {
error: err, error: err,
}); });
setCurrentCallData({ setCurrentCallData({
user_ids: [], UserIds: [],
exists: false, exists: false,
}); });
}); });

View file

@ -17,7 +17,7 @@ export default function Preview() {
}; };
} }
void Promise.all(currentCallData.user_ids.map((id) => get(id))) void Promise.all(currentCallData.UserIds.map((id) => get(id)))
.then((users) => { .then((users) => {
if (!active) { if (!active) {
return; return;
@ -44,7 +44,7 @@ export default function Preview() {
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{data.map((user) => { {data.map((user) => {
return ( return (
<p key={user.user_id} className="text-2xl"> <p key={user.UserId} className="text-2xl">
User: {user.display} User: {user.display}
</p> </p>
); );

View file

@ -6,19 +6,19 @@ import type { RawMessages } from "../values";
* @param send Parameter send. * @param send Parameter send.
* @param amount Parameter amount. * @param amount Parameter amount.
* @param offset Parameter offset. * @param offset Parameter offset.
* @param user_id Parameter user_id. * @param UserId Parameter UserId.
* @returns Promise<RawMessages>. * @returns Promise<RawMessages>.
*/ */
export async function getMessages( export async function getMessages(
send: BoundSendFn, send: BoundSendFn,
amount: number, amount: number,
offset: number, offset: number,
user_id: number, UserId: number,
): Promise<RawMessages> { ): Promise<RawMessages> {
const messages = await send("messages_get", { const messages = await send("messages_get", {
amount: amount, amount: amount,
offset: offset, offset: offset,
user_id: user_id, UserId,
}); });
if (messages.type.startsWith("error")) { if (messages.type.startsWith("error")) {

View file

@ -73,11 +73,11 @@ export default function InputComponent({
const reference = addLiveMessage({ const reference = addLiveMessage({
height: 0, height: 0,
not_encrypted: true, NotEncrypted: true,
send_time: time, SendTime: time,
content: currentValue, content: currentValue,
sent_by_self: true, SentBySelf: true,
message_state: "awaiting", MessageState: "awaiting",
}); });
log(3, "chat", "purple", "Live message added, encrypting..."); log(3, "chat", "purple", "Live message added, encrypting...");
@ -97,14 +97,14 @@ export default function InputComponent({
send("message_send", { send("message_send", {
height: 0, height: 0,
content: encryptedContext, content: encryptedContext,
receiver_id: userId, ReceiverId: userId,
send_time: time, SendTime: time,
}).catch((e) => { }).catch((e) => {
log(0, "Chat", "red", "Failed to send message", e, { log(0, "Chat", "red", "Failed to send message", e, {
content: currentValue, content: currentValue,
encryptedContext, encryptedContext,
receiver_id: userId, ReceiverId: userId,
send_time: time, SendTime: time,
}); });
reference.setFailed(true); reference.setFailed(true);
toast("error", "Failed to send message"); toast("error", "Failed to send message");

View file

@ -41,13 +41,13 @@ function MessageComponent({
}; };
user: User | null; user: User | null;
}) { }) {
const actuallyFailed = message.failed && message.message_state === "awaiting"; const actuallyFailed = message.failed && message.MessageState === "awaiting";
// Fade-in // Fade-in
const [hasFadedIn, setHasFadedIn] = useState(false); const [hasFadedIn, setHasFadedIn] = useState(false);
const opacityClass = !hasFadedIn const opacityClass = !hasFadedIn
? "opacity-0" ? "opacity-0"
: actuallyFailed || message.message_state === "awaiting" : actuallyFailed || message.MessageState === "awaiting"
? "opacity-50" ? "opacity-50"
: "opacity-100"; : "opacity-100";
useEffect(() => { useEffect(() => {
@ -80,21 +80,21 @@ function MessageComponent({
const readConfirmations = await load("settings.read_confirmations"); const readConfirmations = await load("settings.read_confirmations");
if (readConfirmations) { if (readConfirmations) {
if (!user?.user_id) return; if (!user?.UserId) return;
await send("message_state", { await send("message_state", {
chat_partner_id: user?.user_id, ChatPartnerId: user?.UserId,
send_time: message.send_time, SendTime: message.SendTime,
message_state: "read", MessageState: "read",
}); });
} else { } else {
await send("message_state", { await send("message_state", {
chat_partner_id: user?.user_id, ChatPartnerId: user?.UserId,
send_time: message.send_time, SendTime: message.SendTime,
message_state: "received", MessageState: "received",
}); });
} }
}, [load, message.send_time, user?.user_id, send]); }, [load, message.SendTime, user?.UserId, send]);
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
@ -102,7 +102,7 @@ function MessageComponent({
const receiveConfirmations = await load("settings.receive_confirmations"); const receiveConfirmations = await load("settings.receive_confirmations");
if (cancelled) return; if (cancelled) return;
switch (message.message_state) { switch (message.MessageState) {
case "sent": case "sent":
if (receiveConfirmations) { if (receiveConfirmations) {
messageStateReadUpdate(); messageStateReadUpdate();
@ -123,7 +123,7 @@ function MessageComponent({
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [message.message_state, load, messageStateReadUpdate]); }, [message.MessageState, load, messageStateReadUpdate]);
return ( return (
<div <div
@ -132,7 +132,7 @@ function MessageComponent({
> >
<MessageContextMenu <MessageContextMenu
content={message.content} content={message.content}
messageId={message.send_time} messageId={message.SendTime}
> >
<div <div
className={cn( className={cn(
@ -147,7 +147,7 @@ function MessageComponent({
<> <>
{grouped ? ( {grouped ? (
<p className="w-9 text-xs group-hover:visible invisible text-muted-foreground"> <p className="w-9 text-xs group-hover:visible invisible text-muted-foreground">
{new Date(message.send_time).toLocaleString([], { {new Date(message.SendTime).toLocaleString([], {
hour: "2-digit", hour: "2-digit",
minute: "2-digit", minute: "2-digit",
})} })}
@ -160,7 +160,7 @@ function MessageComponent({
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
)} )}
{message.failed && message.message_state === "awaiting" && ( {message.failed && message.MessageState === "awaiting" && (
<Tooltip> <Tooltip>
<TooltipContent> <TooltipContent>
<p>Failed to send message</p> <p>Failed to send message</p>
@ -192,22 +192,22 @@ function MessageComponent({
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<p className="font-medium">{user.display}</p> <p className="font-medium">{user.display}</p>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{new Date(message.send_time).toLocaleString([], { {new Date(message.SendTime).toLocaleString([], {
hour: "2-digit", hour: "2-digit",
minute: "2-digit", minute: "2-digit",
})} })}
</p> </p>
<div> <div>
{message.message_state === "read" ? ( {message.MessageState === "read" ? (
<Check <Check
size={12} size={12}
color="var(--primary-foreground-alt)" color="var(--primary-foreground-alt)"
/> />
) : message.message_state === "received" ? ( ) : message.MessageState === "received" ? (
<Check size={12} color="var(--muted-foreground)" /> <Check size={12} color="var(--muted-foreground)" />
) : message.message_state === "sent" ? ( ) : message.MessageState === "sent" ? (
<RefreshCw size={12} color="var(--muted-foreground)" /> <RefreshCw size={12} color="var(--muted-foreground)" />
) : message.message_state === "sending" ? ( ) : message.MessageState === "sending" ? (
<Ellipse size={12} color="var(--muted-foreground)" /> <Ellipse size={12} color="var(--muted-foreground)" />
) : null} ) : null}
</div> </div>
@ -231,11 +231,11 @@ function MessageComponent({
export default React.memo(MessageComponent, (prev, next) => { export default React.memo(MessageComponent, (prev, next) => {
return ( return (
prev.message.send_time === next.message.send_time && prev.message.SendTime === next.message.SendTime &&
prev.message.content === next.message.content && prev.message.content === next.message.content &&
prev.message.height === next.message.height && prev.message.height === next.message.height &&
prev.message.sent_by_self === next.message.sent_by_self && prev.message.SentBySelf === next.message.SentBySelf &&
prev.message.message_state === next.message.message_state && prev.message.MessageState === next.message.MessageState &&
prev.message.failed === next.message.failed && prev.message.failed === next.message.failed &&
prev.grouped === next.grouped && prev.grouped === next.grouped &&
prev.user === next.user prev.user === next.user

View file

@ -24,23 +24,23 @@ export const context = createContext<contextType | undefined>(undefined);
const queryClient = new QueryClient(); const queryClient = new QueryClient();
function updateMessageStateBySendTime< function updateMessageStateBySendTime<
T extends { send_time: number; message_state: RawMessage["message_state"] }, T extends { SendTime: number; MessageState: RawMessage["MessageState"] },
>( >(
messages: T[], messages: T[],
sendTime: number, sendTime: number,
messageState: RawMessage["message_state"], messageState: RawMessage["MessageState"],
): { next: T[]; updated: boolean } { ): { next: T[]; updated: boolean } {
let updated = false; let updated = false;
const next = messages.map((item) => { const next = messages.map((item) => {
if (item.send_time !== sendTime || item.message_state === messageState) { if (item.SendTime !== sendTime || item.MessageState === messageState) {
return item; return item;
} }
updated = true; updated = true;
return { return {
...item, ...item,
message_state: messageState, MessageState: messageState,
}; };
}); });
@ -105,8 +105,8 @@ export default function Provider(props: { children: ReactNode }) {
const ownData = await get(ownId); const ownData = await get(ownId);
const sharedSecret = await getSharedSecret( const sharedSecret = await getSharedSecret(
privateKey, privateKey,
ownData.public_key, ownData.PublicKey,
recipientData.public_key, recipientData.PublicKey,
); );
if (active) { if (active) {
@ -135,7 +135,7 @@ export default function Provider(props: { children: ReactNode }) {
const messages = await send("messages_get", { const messages = await send("messages_get", {
amount, amount,
offset, offset,
user_id: userIdValue, UserId: userIdValue,
}); });
if (messages.type.startsWith("error")) { if (messages.type.startsWith("error")) {
@ -143,14 +143,14 @@ export default function Provider(props: { children: ReactNode }) {
} }
const rawMessages = messages.data.messages; const rawMessages = messages.data.messages;
const sorted = [...rawMessages].sort((a, b) => a.send_time - b.send_time); const sorted = [...rawMessages].sort((a, b) => a.SendTime - b.SendTime);
if (sorted.length > 0) { if (sorted.length > 0) {
const fetchedSendTimes = new Set(sorted.map((item) => item.send_time)); const fetchedSendTimes = new Set(sorted.map((item) => item.SendTime));
setLiveMessagesState((prev) => { setLiveMessagesState((prev) => {
const filtered = prev.filter( const filtered = prev.filter(
(liveMessage) => !fetchedSendTimes.has(liveMessage.send_time), (liveMessage) => !fetchedSendTimes.has(liveMessage.SendTime),
); );
return filtered.length === prev.length ? prev : filtered; return filtered.length === prev.length ? prev : filtered;
@ -179,7 +179,7 @@ export default function Provider(props: { children: ReactNode }) {
globalThis.crypto?.randomUUID?.() ?? globalThis.crypto?.randomUUID?.() ??
`${Date.now()}-${Math.random().toString(36).slice(2)}`; `${Date.now()}-${Math.random().toString(36).slice(2)}`;
if (!message.sent_by_self) { if (!message.SentBySelf) {
moveUserIdToTop(userIdValue); moveUserIdToTop(userIdValue);
} }
@ -219,20 +219,20 @@ export default function Provider(props: { children: ReactNode }) {
} }
const rawData = message.data as { const rawData = message.data as {
chat_partner_id: unknown; ChatPartnerId: unknown;
send_time: unknown; SendTime: unknown;
message_state: RawMessage["message_state"]; MessageState: RawMessage["MessageState"];
}; };
const nextState = { const nextState = {
chat_partner_id: Number(rawData.chat_partner_id), ChatPartnerId: Number(rawData.ChatPartnerId),
send_time: Number(rawData.send_time), SendTime: Number(rawData.SendTime),
message_state: rawData.message_state, MessageState: rawData.MessageState,
}; };
if ( if (
!Number.isFinite(nextState.chat_partner_id) || !Number.isFinite(nextState.ChatPartnerId) ||
!Number.isFinite(nextState.send_time) !Number.isFinite(nextState.SendTime)
) { ) {
log( log(
3, 3,
@ -243,7 +243,7 @@ export default function Provider(props: { children: ReactNode }) {
return; return;
} }
if (nextState.chat_partner_id !== userIdValue) { if (nextState.ChatPartnerId !== userIdValue) {
log( log(
3, 3,
"chat", "chat",
@ -251,7 +251,7 @@ export default function Provider(props: { children: ReactNode }) {
"Cancel message state update due to user ID mismatch", "Cancel message state update due to user ID mismatch",
{ {
expected: userIdValue, expected: userIdValue,
received: nextState.chat_partner_id, received: nextState.ChatPartnerId,
}, },
); );
return; return;
@ -260,8 +260,8 @@ export default function Provider(props: { children: ReactNode }) {
setLiveMessagesState((prev) => { setLiveMessagesState((prev) => {
const { next, updated } = updateMessageStateBySendTime( const { next, updated } = updateMessageStateBySendTime(
prev, prev,
nextState.send_time, nextState.SendTime,
nextState.message_state, nextState.MessageState,
); );
return updated ? next : prev; return updated ? next : prev;
}); });
@ -283,8 +283,8 @@ export default function Provider(props: { children: ReactNode }) {
const pages = current.pages.map((page) => { const pages = current.pages.map((page) => {
const nextPage = updateMessageStateBySendTime( const nextPage = updateMessageStateBySendTime(
page, page,
nextState.send_time, nextState.SendTime,
nextState.message_state, nextState.MessageState,
); );
if (nextPage.updated) { if (nextPage.updated) {

View file

@ -48,7 +48,7 @@ function shouldFetchPreviousPage({
} }
function getMessageRenderKey(message: RawMessage | LiveMessage) { function getMessageRenderKey(message: RawMessage | LiveMessage) {
return "localId" in message ? message.localId : String(message.send_time); return "localId" in message ? message.localId : String(message.SendTime);
} }
function buildMessageChunks( function buildMessageChunks(
@ -184,11 +184,11 @@ export default function Screen() {
const dedupedMessages: RawMessage[] = []; const dedupedMessages: RawMessage[] = [];
for (const message of [...pages].reverse().flat()) { for (const message of [...pages].reverse().flat()) {
if (seenSendTimes.has(message.send_time)) { if (seenSendTimes.has(message.SendTime)) {
continue; continue;
} }
seenSendTimes.add(message.send_time); seenSendTimes.add(message.SendTime);
dedupedMessages.push(message); dedupedMessages.push(message);
} }
@ -199,11 +199,11 @@ export default function Screen() {
const liveWithoutDuplicates = React.useMemo(() => { const liveWithoutDuplicates = React.useMemo(() => {
const historicalSendTimes = new Set( const historicalSendTimes = new Set(
historicalMessages.map((message) => message.send_time), historicalMessages.map((message) => message.SendTime),
); );
return liveMessagesSnapshot.filter( return liveMessagesSnapshot.filter(
(message) => !historicalSendTimes.has(message.send_time), (message) => !historicalSendTimes.has(message.SendTime),
); );
}, [historicalMessages, liveMessagesSnapshot]); }, [historicalMessages, liveMessagesSnapshot]);
@ -559,9 +559,9 @@ export default function Screen() {
const lastMessage = messages[messageIndex - 1]; const lastMessage = messages[messageIndex - 1];
const isGrouped = const isGrouped =
lastMessage && lastMessage &&
lastMessage.sent_by_self === message.sent_by_self && lastMessage.SentBySelf === message.SentBySelf &&
Math.round(lastMessage.send_time / 10000) === Math.round(lastMessage.SendTime / 10000) ===
Math.round(message.send_time / 10000); Math.round(message.SendTime / 10000);
return ( return (
<Message <Message
@ -569,7 +569,7 @@ export default function Screen() {
grouped={isGrouped} grouped={isGrouped}
message={message} message={message}
user={ user={
message.sent_by_self message.SentBySelf
? (messageUsers.own ?? null) ? (messageUsers.own ?? null)
: (messageUsers.peer ?? null) : (messageUsers.peer ?? null)
} }

View file

@ -116,47 +116,15 @@ function getProtocolErrorDetails(error: unknown) {
}; };
} }
function toPascalCase(value: string) {
return value
.split("_")
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join("");
}
function toSnakeCase(value: string) {
return value
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
.toLowerCase();
}
function mapDataKeys(value: unknown, mapKey: (key: string) => string): unknown {
if (Array.isArray(value)) {
return value.map((item) => mapDataKeys(item, mapKey));
}
if (typeof value !== "object" || value === null) {
return value;
}
return Object.fromEntries(
Object.entries(value).map(([key, entry]) => [
mapKey(key),
mapDataKeys(entry, mapKey),
]),
);
}
// Zod schema validation // Zod schema validation
function validateResponse<T extends keyof Schemas & string>( function validateResponse<T extends keyof Schemas & string>(
type: T, type: T,
message: { id?: number; type: string; data: unknown }, message: { id?: number; type: string; data: unknown },
): ProtocolMessage<T> { ): ProtocolMessage<T> {
const appType = APP_TYPES[message.type] ?? message.type; const appType = APP_TYPES[message.type] ?? message.type;
const data = mapDataKeys(message.data, toSnakeCase);
if (appType.startsWith("error")) { if (appType.startsWith("error")) {
return { ...message, type: appType, data } as ProtocolMessage<T>; return { ...message, type: appType } as ProtocolMessage<T>;
} }
const schema = schemas[type]?.response; const schema = schemas[type]?.response;
@ -164,7 +132,7 @@ function validateResponse<T extends keyof Schemas & string>(
return message as ProtocolMessage<T>; return message as ProtocolMessage<T>;
} }
const parsed = schema.safeParse(data); const parsed = schema.safeParse(message.data);
if (!parsed.success) { if (!parsed.success) {
throw new Error( throw new Error(
`Response validation failed for ${type}: ${parsed.error.message}`, `Response validation failed for ${type}: ${parsed.error.message}`,
@ -223,7 +191,7 @@ export function Provider(props: {
const message = await client.request( const message = await client.request(
WIRE_TYPES[type], WIRE_TYPES[type],
mapDataKeys(data ?? {}, toPascalCase) as Record<string, unknown>, (data ?? {}) as Record<string, unknown>,
options, options,
); );
return validateResponse(type, message); return validateResponse(type, message);
@ -282,10 +250,10 @@ export function Provider(props: {
const interval = setInterval(async () => { const interval = setInterval(async () => {
try { try {
const originalNow = Date.now(); const originalNow = Date.now();
const data = await send("ping", { last_ping: originalNow }); const data = await send("ping", { LastPing: originalNow });
setOwnPing(Date.now() - originalNow); setOwnPing(Date.now() - originalNow);
const remotePing = data.data.ping_iota; const remotePing = data.data.PingIota;
if (typeof remotePing === "number") { if (typeof remotePing === "number") {
setIotaPing(remotePing); setIotaPing(remotePing);
} }

View file

@ -35,41 +35,41 @@ export default function Provider(props: { children: React.ReactNode }) {
useEffect(() => { useEffect(() => {
return subscribePush(async (ttpMessage) => { return subscribePush(async (ttpMessage) => {
if (ttpMessage.type === "message_live") { if (ttpMessage.type === "message_live") {
const { message, sender_id } = ttpMessage.data as { const { message, SenderId } = ttpMessage.data as {
message: z.infer<typeof messageSchema>; message: z.infer<typeof messageSchema>;
sender_id: number; SenderId: number;
}; };
const user = await get(sender_id); const user = await get(SenderId);
const decryptedContent = await decryptText( const decryptedContent = await decryptText(
await getSharedSecret( await getSharedSecret(
await load("private_key"), await load("private_key"),
await get(await load("user_id")).then((data) => data.public_key), await get(await load("user_id")).then((data) => data.PublicKey),
user.public_key, user.PublicKey,
), ),
message.content, message.content,
); );
// Update message state // Update message state
if (userId === sender_id) { if (userId === SenderId) {
addLiveMessage({ addLiveMessage({
...message, ...message,
content: decryptedContent, content: decryptedContent,
sent_by_self: false, SentBySelf: false,
}); });
return; return;
} }
// todo: add notification symbol to conversation cards (incl. message start) // todo: add notification symbol to conversation cards (incl. message start)
moveUserIdToTop(sender_id); moveUserIdToTop(SenderId);
if (await load("settings.receive_confirmations")) { if (await load("settings.receive_confirmations")) {
void send( void send(
"message_state", "message_state",
{ {
message_state: "received", MessageState: "received",
}, },
{ {
id: ttpMessage.id, id: ttpMessage.id,
@ -87,14 +87,14 @@ export default function Provider(props: { children: React.ReactNode }) {
body: decryptedContent, body: decryptedContent,
icon: user.avatar || user.display.slice(0, 2).toUpperCase(), icon: user.avatar || user.display.slice(0, 2).toUpperCase(),
badge: user.avatar || user.display.slice(0, 2).toUpperCase(), badge: user.avatar || user.display.slice(0, 2).toUpperCase(),
tag: `message-${user.user_id}`, tag: `message-${user.UserId}`,
silent: true, silent: true,
}); });
notification.onclick = () => { notification.onclick = () => {
window.focus(); window.focus();
navigate({ navigate({
to: `/chat?id=${user.user_id}`, to: `/chat?id=${user.UserId}`,
}); });
notification.close(); notification.close();

View file

@ -14,28 +14,28 @@ const fileFromMessage = z.object({
export const message = z.object({ export const message = z.object({
height: z.number(), height: z.number(),
not_encrypted: z.boolean().optional(), NotEncrypted: z.boolean().optional(),
sent_by_self: z.boolean().optional(), SentBySelf: z.boolean().optional(),
send_time: z.number(), SendTime: z.number(),
content: z.base64(), content: z.base64(),
files: z.array(fileFromMessage).optional(), files: z.array(fileFromMessage).optional(),
tint: z.string().length(7).startsWith("#").optional(), tint: z.string().length(7).startsWith("#").optional(),
avatar: z.boolean().optional(), avatar: z.boolean().optional(),
display: z.boolean().optional(), display: z.boolean().optional(),
message_state: z MessageState: z
.enum(["read", "received", "sent", "sending", "awaiting"]) // awaiting for 'internal' use .enum(["read", "received", "sent", "sending", "awaiting"]) // awaiting for 'internal' use
.default("received"), .default("received"),
}); });
export const failedUser = { export const failedUser = {
display: "Failed", display: "Failed",
iota_id: 0, IotaId: 0,
omikron_connections: [], OmikronConnections: [],
online_status: "user_borked", OnlineStatus: "user_borked",
public_key: "", PublicKey: "",
sub_end: 0, SubEnd: 0,
sub_level: 0, SubLevel: 0,
user_id: 0, UserId: 0,
username: "unknown", username: "unknown",
} as z.infer<typeof mtp.get_user_data.response>; } as z.infer<typeof mtp.get_user_data.response>;
@ -43,12 +43,12 @@ const authPayload = z.object({
communities: z.array(z.object({})).optional(), communities: z.array(z.object({})).optional(),
contacts: z.array( contacts: z.array(
z.object({ z.object({
last_message_at: z.number(), LastMessageAt: z.number(),
user_id: z.number(), UserId: z.number(),
last_message: z LastMessage: z
.object({ .object({
content: z.base64(), content: z.base64(),
sender_id: z.number(), SenderId: z.number(),
}) })
.optional(), .optional(),
messages: z.array(message), messages: z.array(message),
@ -56,9 +56,9 @@ const authPayload = z.object({
), ),
calls: z.array( calls: z.array(
z.object({ z.object({
call_id: z.string(), CallId: z.string(),
call_secret: z.base64().optional(), CallSecret: z.base64().optional(),
call_members: z.array(z.number()), CallMembers: z.array(z.number()),
}), }),
), ),
}); });
@ -92,10 +92,10 @@ const user = z.object({
about: z.string().max(255).optional(), about: z.string().max(255).optional(),
avatar: z.string().optional(), avatar: z.string().optional(),
display: z.string().min(1).max(15), display: z.string().min(1).max(15),
iota_id: z.number(), IotaId: z.number(),
omikron_connections: z.array(z.number()), OmikronConnections: z.array(z.number()),
omikron_id: z.number().optional(), OmikronId: z.number().optional(),
online_status: z.enum([ OnlineStatus: z.enum([
"user_offline", "user_offline",
"user_online", "user_online",
"user_dnd", "user_dnd",
@ -106,11 +106,11 @@ const user = z.object({
"iota_online", "iota_online",
"iota_borked", "iota_borked",
]), ]),
public_key: z.base64(), PublicKey: z.base64(),
status: z.string().max(15).optional(), status: z.string().max(15).optional(),
sub_end: z.number(), SubEnd: z.number(),
sub_level: z.number(), SubLevel: z.number(),
user_id: z.number(), UserId: z.number(),
username: z.string().min(1).max(15), username: z.string().min(1).max(15),
}); });
export const mtp = { export const mtp = {
@ -120,7 +120,7 @@ export const mtp = {
}, },
get_user_data: { get_user_data: {
request: z.object({ request: z.object({
user_id: z.number().optional(), UserId: z.number().optional(),
username: z.string().optional(), username: z.string().optional(),
}), }),
response: user, response: user,
@ -131,22 +131,22 @@ export const mtp = {
}, },
ping: { ping: {
request: z.object({ request: z.object({
last_ping: z.number(), LastPing: z.number(),
}), }),
response: z.object({ response: z.object({
ping_iota: z.number(), PingIota: z.number(),
}), }),
}, },
message_live: { message_live: {
request: z.object({}).optional(), request: z.object({}).optional(),
response: z.object({ response: z.object({
sender_id: z.number(), SenderId: z.number(),
message, message,
}), }),
}, },
messages_get: { messages_get: {
request: z.object({ request: z.object({
user_id: z.number(), UserId: z.number(),
amount: z.number(), amount: z.number(),
offset: z.number(), offset: z.number(),
}), }),
@ -158,35 +158,35 @@ export const mtp = {
request: z.object({ request: z.object({
height: z.number(), height: z.number(),
content: z.base64(), content: z.base64(),
receiver_id: z.number(), ReceiverId: z.number(),
send_time: z.number(), SendTime: z.number(),
files: z.array(fileFromMessage).optional(), files: z.array(fileFromMessage).optional(),
}), }),
response: z.object({}), response: z.object({}),
}, },
add_conversation: { add_conversation: {
request: z.object({ request: z.object({
chat_partner_id: z.number().optional(), ChatPartnerId: z.number().optional(),
chat_partner_name: z.string().min(1).max(15).optional(), ChatPartnerName: z.string().min(1).max(15).optional(),
}), }),
response: z.object({}), response: z.object({}),
}, },
message_state: { message_state: {
request: z request: z
.object({ .object({
chat_partner_id: z.number(), ChatPartnerId: z.number(),
send_time: z.number(), SendTime: z.number(),
message_state: message.shape.message_state, MessageState: message.shape.MessageState,
}) })
.or( .or(
z.object({ z.object({
message_state: message.shape.message_state, MessageState: message.shape.MessageState,
}), }),
), ),
response: z.object({ response: z.object({
chat_partner_id: z.number(), ChatPartnerId: z.number(),
message_state: message.shape.message_state, MessageState: message.shape.MessageState,
send_time: z.number(), SendTime: z.number(),
}), }),
}, },
@ -200,7 +200,7 @@ export const mtp = {
}, },
authenticate_app: { authenticate_app: {
request: z.object({ request: z.object({
app_identifier: z.string(), AppIdentifier: z.string(),
}), }),
response: z.object({ response: z.object({
challenge: z.base64(), challenge: z.base64(),
@ -208,8 +208,8 @@ export const mtp = {
}, },
create_app: { create_app: {
request: z.object({ request: z.object({
app_public_key: z.base64(), AppPublicKey: z.base64(),
app_identifier: z.string(), AppIdentifier: z.string(),
}), }),
response: z.object({}), response: z.object({}),
}, },
@ -217,30 +217,30 @@ export const mtp = {
// Calls // Calls
call_token: { call_token: {
request: z.object({ request: z.object({
call_id: z.string(), CallId: z.string(),
}), }),
response: z.object({ response: z.object({
call_token: z.string(), CallToken: z.string(),
}), }),
}, },
call_data: { call_data: {
request: z.object({ request: z.object({
call_id: z.string(), CallId: z.string(),
}), }),
response: z.object({ response: z.object({
user_ids: z.array(z.number()), UserIds: z.array(z.number()),
}), }),
}, },
call_invite: { call_invite: {
request: z.object({ request: z.object({
call_id: z.string(), CallId: z.string(),
call_secret: z.base64(), CallSecret: z.base64(),
receiver_id: z.number(), ReceiverId: z.number(),
}), }),
response: z.object({ response: z.object({
call_id: z.string().optional(), CallId: z.string().optional(),
call_secret: z.base64().optional(), CallSecret: z.base64().optional(),
sender_id: z.number().optional(), SenderId: z.number().optional(),
}), }),
}, },
error_no_iota: { error_no_iota: {
@ -355,7 +355,7 @@ export const storageDefaults: Storage = {
// User Status // User Status
export function getStatusColor( export function getStatusColor(
status: z.infer<typeof mtp.get_user_data.response.shape.online_status>, status: z.infer<typeof mtp.get_user_data.response.shape.OnlineStatus>,
) { ) {
switch (status) { switch (status) {
case "user_online": case "user_online":

View file

@ -29,7 +29,7 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
const calls = [ const calls = [
...freshCalls, ...freshCalls,
...localCalls.filter( ...localCalls.filter(
(call) => !freshCalls.some((fresh) => fresh.call_id === call.call_id), (call) => !freshCalls.some((fresh) => fresh.CallId === call.CallId),
), ),
]; ];
@ -40,7 +40,7 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
...freshContacts, ...freshContacts,
...cachedData.filter( ...cachedData.filter(
(item) => (item) =>
!freshContacts.some((fresh) => fresh.user_id === item.user_id), !freshContacts.some((fresh) => fresh.UserId === item.UserId),
), ),
]); ]);
}); });
@ -69,7 +69,7 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
const moveUserIdToTop = (userId: number) => { const moveUserIdToTop = (userId: number) => {
setContacts((prevContacts) => { setContacts((prevContacts) => {
const userIndex = prevContacts.findIndex( const userIndex = prevContacts.findIndex(
(contact) => contact.user_id === userId, (contact) => contact.UserId === userId,
); );
if (userIndex === -1) return prevContacts; if (userIndex === -1) return prevContacts;
const [user] = prevContacts.splice(userIndex, 1); const [user] = prevContacts.splice(userIndex, 1);
@ -79,13 +79,13 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
const insertContact = (userId: number) => { const insertContact = (userId: number) => {
setContacts((prevContacts) => { setContacts((prevContacts) => {
if (prevContacts.some((contact) => contact.user_id === userId)) { if (prevContacts.some((contact) => contact.UserId === userId)) {
return prevContacts; return prevContacts;
} }
const newUser = { const newUser = {
user_id: userId, UserId: userId,
last_message_at: new Date().getTime(), LastMessageAt: new Date().getTime(),
messages: [], messages: [],
} satisfies Contacts[0]; } satisfies Contacts[0];
@ -95,7 +95,7 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
const insertCall = (call: Calls[number]) => { const insertCall = (call: Calls[number]) => {
setLocalCalls((prevCalls) => { setLocalCalls((prevCalls) => {
if (prevCalls.some((prevCall) => prevCall.call_id === call.call_id)) { if (prevCalls.some((prevCall) => prevCall.CallId === call.CallId)) {
return prevCalls; return prevCalls;
} }

View file

@ -62,7 +62,7 @@ export default function Wrapper({ children }: { children: ReactNode }) {
// Get Shared Secret // Get Shared Secret
const sharedSecret = await getSharedSecret( const sharedSecret = await getSharedSecret(
await load("private_key"), await load("private_key"),
user.public_key, user.PublicKey,
appPublicKey, appPublicKey,
).catch((err) => { ).catch((err) => {
log(1, "tauth", "red", "Failed to get shared secret", err, { log(1, "tauth", "red", "Failed to get shared secret", err, {
@ -92,8 +92,8 @@ export default function Wrapper({ children }: { children: ReactNode }) {
// Save Session // Save Session
await send("create_app", { await send("create_app", {
app_public_key: appPublicKey, AppPublicKey: appPublicKey,
app_identifier: identifier, AppIdentifier: identifier,
}); });
// Open Redirect URL // Open Redirect URL

View file

@ -47,7 +47,7 @@ export default function UserProvider(props: { children: React.ReactNode }) {
} }
const request = (async () => { const request = (async () => {
const userData = await send("get_user_data", { user_id: userId }); const userData = await send("get_user_data", { UserId: userId });
const user = { const user = {
...userData.data, ...userData.data,
avatar: userData.data.avatar avatar: userData.data.avatar