Squashed bugs

This commit is contained in:
Alois 2026-04-13 17:37:55 +02:00
commit 126f397d97
9 changed files with 44 additions and 43 deletions

View file

@ -24,7 +24,6 @@
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true, "noUncheckedSideEffectImports": true,
"baseUrl": ".",
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"]
} }

View file

@ -3,6 +3,10 @@ import globals from "globals";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
import reactHooks from "eslint-plugin-react-hooks"; import reactHooks from "eslint-plugin-react-hooks";
import * as tsParser from "@typescript-eslint/parser"; import * as tsParser from "@typescript-eslint/parser";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
export default [ export default [
{ {
@ -14,6 +18,9 @@ export default [
files: ["**/*.{ts,tsx}"], files: ["**/*.{ts,tsx}"],
languageOptions: { languageOptions: {
parser: tsParser, parser: tsParser,
parserOptions: {
tsconfigRootDir,
},
globals: { globals: {
...globals.browser, ...globals.browser,
...globals.node, ...globals.node,

View file

@ -74,7 +74,7 @@ export default function InputComponent({
const reference = addLiveMessage({ const reference = addLiveMessage({
height, height,
not_encrypted: true, not_encrypted: true,
timestamp: time, send_time: time,
content: currentValue, content: currentValue,
sent_by_self: true, sent_by_self: true,
message_state: "awaiting", message_state: "awaiting",
@ -86,13 +86,13 @@ export default function InputComponent({
height, height,
content: encryptedContext, content: encryptedContext,
receiver_id: userId, receiver_id: userId,
timestamp: time, send_time: 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, receiver_id: userId,
timestamp: time, send_time: time,
}); });
reference.setFailed(true); reference.setFailed(true);
toast("error", "Failed to send message"); toast("error", "Failed to send message");
@ -108,7 +108,7 @@ export default function InputComponent({
className={cn( className={cn(
"rounded-none border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]", "rounded-none border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]",
isMobile isMobile
? "border-0 border-t-1 fixed w-full bottom-0 left-0 px-2" ? "border-0 border-t fixed w-full bottom-0 left-0 px-2"
: "rounded-t-xl", : "rounded-t-xl",
)} )}
> >
@ -123,7 +123,7 @@ export default function InputComponent({
message={{ message={{
height: 0, height: 0,
not_encrypted: true, not_encrypted: true,
timestamp: 0, send_time: 0,
content: value, content: value,
sent_by_self: true, sent_by_self: true,
message_state: "awaiting", message_state: "awaiting",

View file

@ -157,7 +157,7 @@ export default React.memo(MessageComponent, (prev, next) => {
return ( return (
prev.notEncrypted === next.notEncrypted && prev.notEncrypted === next.notEncrypted &&
prev.measureRef === next.measureRef && prev.measureRef === next.measureRef &&
prev.message.timestamp === next.message.timestamp && prev.message.send_time === next.message.send_time &&
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.sent_by_self === next.message.sent_by_self &&

View file

@ -22,17 +22,17 @@ export const context = createContext<contextType | undefined>(undefined);
const queryClient = new QueryClient(); const queryClient = new QueryClient();
function updateMessageStateByTimestamp< function updateMessageStateBySendTime<
T extends { timestamp: number; message_state: RawMessage["message_state"] }, T extends { send_time: number; message_state: RawMessage["message_state"] },
>( >(
messages: T[], messages: T[],
timestamp: number, sendTime: number,
messageState: RawMessage["message_state"], messageState: RawMessage["message_state"],
): { 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.timestamp !== timestamp || item.message_state === messageState) { if (item.send_time !== sendTime || item.message_state === messageState) {
return item; return item;
} }
@ -54,7 +54,7 @@ function updateMessageStateByTimestamp<
* @param props Parameter props. * @param props Parameter props.
* @returns unknown. * @returns unknown.
*/ */
export function Provider(props: { children: ReactNode }) { export default function Provider(props: { children: ReactNode }) {
const { getSharedSecret } = useCrypto(); const { getSharedSecret } = useCrypto();
const { get } = useUser(); const { get } = useUser();
const { load } = useStorage(); const { load } = useStorage();
@ -141,14 +141,14 @@ export function Provider(props: { children: ReactNode }) {
} }
const rawMessages = messages.data.messages; const rawMessages = messages.data.messages;
const sorted = [...rawMessages].sort((a, b) => a.timestamp - b.timestamp); const sorted = [...rawMessages].sort((a, b) => a.send_time - b.send_time);
if (sorted.length > 0) { if (sorted.length > 0) {
const fetchedTimestamps = new Set(sorted.map((item) => item.timestamp)); const fetchedSendTimes = new Set(sorted.map((item) => item.send_time));
setLiveMessagesState((prev) => { setLiveMessagesState((prev) => {
const filtered = prev.filter( const filtered = prev.filter(
(liveMessage) => !fetchedTimestamps.has(liveMessage.timestamp), (liveMessage) => !fetchedSendTimes.has(liveMessage.send_time),
); );
return filtered.length === prev.length ? prev : filtered; return filtered.length === prev.length ? prev : filtered;
@ -200,19 +200,19 @@ export function Provider(props: { children: ReactNode }) {
const rawData = message.data as { const rawData = message.data as {
chat_partner_id: unknown; chat_partner_id: unknown;
timestamp: unknown; send_time: unknown;
message_state: RawMessage["message_state"]; message_state: RawMessage["message_state"];
}; };
const nextState = { const nextState = {
chat_partner_id: Number(rawData.chat_partner_id), chat_partner_id: Number(rawData.chat_partner_id),
timestamp: Number(rawData.timestamp), send_time: Number(rawData.send_time),
message_state: rawData.message_state, message_state: rawData.message_state,
}; };
if ( if (
!Number.isFinite(nextState.chat_partner_id) || !Number.isFinite(nextState.chat_partner_id) ||
!Number.isFinite(nextState.timestamp) !Number.isFinite(nextState.send_time)
) { ) {
log( log(
3, 3,
@ -238,9 +238,9 @@ export function Provider(props: { children: ReactNode }) {
} }
setLiveMessagesState((prev) => { setLiveMessagesState((prev) => {
const { next, updated } = updateMessageStateByTimestamp( const { next, updated } = updateMessageStateBySendTime(
prev, prev,
nextState.timestamp, nextState.send_time,
nextState.message_state, nextState.message_state,
); );
return updated ? next : prev; return updated ? next : prev;
@ -257,9 +257,9 @@ export function Provider(props: { children: ReactNode }) {
let updated = false; let updated = false;
const pages = current.pages.map((page) => { const pages = current.pages.map((page) => {
const nextPage = updateMessageStateByTimestamp( const nextPage = updateMessageStateBySendTime(
page, page,
nextState.timestamp, nextState.send_time,
nextState.message_state, nextState.message_state,
); );

View file

@ -80,11 +80,11 @@ export default function Screen() {
return liveMessagesSnapshot; return liveMessagesSnapshot;
} }
const historicalTimestamps = new Set( const historicalSendTimes = new Set(
historicalMessages.map((message) => message.timestamp), historicalMessages.map((message) => message.send_time),
); );
const liveWithoutDuplicates = liveMessagesSnapshot.filter( const liveWithoutDuplicates = liveMessagesSnapshot.filter(
(message) => !historicalTimestamps.has(message.timestamp), (message) => !historicalSendTimes.has(message.send_time),
); );
return [...historicalMessages, ...liveWithoutDuplicates]; return [...historicalMessages, ...liveWithoutDuplicates];
@ -97,7 +97,7 @@ export default function Screen() {
}, [messages]); }, [messages]);
const getItemKey = React.useCallback((index: number) => { const getItemKey = React.useCallback((index: number) => {
return messagesRef.current[index]?.timestamp ?? index; return messagesRef.current[index]?.send_time ?? index;
}, []); }, []);
// eslint-disable-next-line react-hooks/incompatible-library // eslint-disable-next-line react-hooks/incompatible-library
@ -167,7 +167,11 @@ export default function Screen() {
} }
setLastLiveMessageCount(count); setLastLiveMessageCount(count);
}, [lastLiveMessageCount, liveMessagesSnapshot.length, stickyBottomThreshold]); }, [
lastLiveMessageCount,
liveMessagesSnapshot.length,
stickyBottomThreshold,
]);
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
if ( if (
@ -291,7 +295,7 @@ export default function Screen() {
return ( return (
<div <div
key={message.timestamp} key={message.send_time}
data-index={virtualRow.index} data-index={virtualRow.index}
ref={virtualizer.measureElement} ref={virtualizer.measureElement}
style={{ style={{

View file

@ -13,7 +13,7 @@ const message = z.object({
height: z.number(), height: z.number(),
not_encrypted: z.boolean().optional(), not_encrypted: z.boolean().optional(),
sent_by_self: z.boolean(), sent_by_self: z.boolean(),
timestamp: z.number(), send_time: 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(),
@ -111,7 +111,7 @@ export const ttp = {
request: z.object({}), request: z.object({}),
response: z.object({ response: z.object({
sender_id: z.number(), sender_id: z.number(),
timestamp: z.number(), send_time: z.number(),
message, message,
}), }),
}, },
@ -130,7 +130,7 @@ export const ttp = {
height: z.number(), height: z.number(),
content: z.base64(), content: z.base64(),
receiver_id: z.number(), receiver_id: z.number(),
timestamp: z.number(), send_time: z.number(),
files: z.array(fileFromMessage).optional(), files: z.array(fileFromMessage).optional(),
}), }),
response: z.object({}), response: z.object({}),
@ -145,13 +145,13 @@ export const ttp = {
message_state: { message_state: {
request: z.object({ request: z.object({
chat_partner_id: z.number(), chat_partner_id: z.number(),
timestamp: z.number(), send_time: z.number(),
message_state: message.shape.message_state, message_state: message.shape.message_state,
}), }),
response: z.object({ response: z.object({
chat_partner_id: z.number(), chat_partner_id: z.number(),
message_state: message.shape.message_state, message_state: message.shape.message_state,
timestamp: z.number(), send_time: z.number(),
}), }),
}, },

View file

@ -155,7 +155,7 @@ const TTPContext = createContext<ContextType | undefined>(undefined);
* @param props Component props with children. * @param props Component props with children.
* @returns Loading, error, or provider-wrapped JSX. * @returns Loading, error, or provider-wrapped JSX.
*/ */
export default function Provider(props: { export function Provider(props: {
children: ReactNode; children: ReactNode;
blockConnection?: boolean; blockConnection?: boolean;
}) { }) {

View file

@ -1,9 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"baseUrl": ".",
"paths": {
"@app/*": ["packages/*/src", "apps/*/src"]
}
}
}