diff --git a/packages/react-sdk/src/helpers/caching/contentTypes/attachment.test.ts b/packages/react-sdk/src/helpers/caching/contentTypes/attachment.test.ts index 932727da..e90bd91c 100644 --- a/packages/react-sdk/src/helpers/caching/contentTypes/attachment.test.ts +++ b/packages/react-sdk/src/helpers/caching/contentTypes/attachment.test.ts @@ -15,7 +15,7 @@ import { hasAttachment, attachmentContentTypeConfig, } from "./attachment"; -import { type CachedMessageWithId } from "@/helpers/caching/messages"; +import { type CachedMessage } from "@/helpers/caching/messages"; import { createRandomWallet } from "@/helpers/testing"; const testWallet = createRandomWallet(); @@ -53,7 +53,7 @@ describe("ContentTypeRemoteAttachment caching", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const attachment = getAttachment(testMessage); expect(attachment).toEqual(testContent); @@ -82,7 +82,7 @@ describe("ContentTypeRemoteAttachment caching", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const attachment2 = getAttachment(testMessage2); expect(attachment2).toEqual(testContent2); @@ -101,7 +101,7 @@ describe("ContentTypeRemoteAttachment caching", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const attachment3 = getAttachment(testMessage3); expect(attachment3).toBeUndefined(); @@ -129,7 +129,7 @@ describe("ContentTypeRemoteAttachment caching", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const attachment = hasAttachment(testMessage); expect(attachment).toBe(true); @@ -148,7 +148,7 @@ describe("ContentTypeRemoteAttachment caching", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const attachment2 = hasAttachment(testMessage2); expect(attachment2).toBe(false); diff --git a/packages/react-sdk/src/helpers/caching/contentTypes/reaction.test.ts b/packages/react-sdk/src/helpers/caching/contentTypes/reaction.test.ts index 88cf5180..a7288407 100644 --- a/packages/react-sdk/src/helpers/caching/contentTypes/reaction.test.ts +++ b/packages/react-sdk/src/helpers/caching/contentTypes/reaction.test.ts @@ -16,7 +16,7 @@ import { } from "./reaction"; import { saveMessage, - type CachedMessageWithId, + type CachedMessage, getMessageByXmtpID, } from "@/helpers/caching/messages"; import { getDbInstance, clearCache } from "@/helpers/caching/db"; @@ -106,7 +106,7 @@ describe("ContentTypeReaction", () => { senderAddress: "testWalletAddress", uuid: "testUuid1", xmtpID: "testXmtpId1", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await saveMessage(testTextMessage, db); @@ -131,7 +131,7 @@ describe("ContentTypeReaction", () => { senderAddress: "testWalletAddress", uuid: "testUuid2", xmtpID: "testXmtpId2", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const updateConversationMetadata = vi.fn(); await processReaction({ @@ -173,7 +173,7 @@ describe("ContentTypeReaction", () => { senderAddress: "testWalletAddress", uuid: "testUuid3", xmtpID: "testXmtpId3", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await processReaction({ client: testClient, @@ -216,7 +216,7 @@ describe("ContentTypeReaction", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const updateConversationMetadata = vi.fn(); await processReaction({ diff --git a/packages/react-sdk/src/helpers/caching/contentTypes/reply.test.ts b/packages/react-sdk/src/helpers/caching/contentTypes/reply.test.ts index a76acb1a..29ea7464 100644 --- a/packages/react-sdk/src/helpers/caching/contentTypes/reply.test.ts +++ b/packages/react-sdk/src/helpers/caching/contentTypes/reply.test.ts @@ -13,7 +13,7 @@ import { } from "./reply"; import { saveMessage, - type CachedMessageWithId, + type CachedMessage, getMessageByXmtpID, } from "@/helpers/caching/messages"; import { getDbInstance, clearCache } from "@/helpers/caching/db"; @@ -68,7 +68,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid1", xmtpID: "testXmtpId1", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await saveMessage(testTextMessage, db); @@ -92,7 +92,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid2", xmtpID: "testXmtpId2", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await saveMessage(testReplyMessage, db); @@ -145,7 +145,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const updateConversationMetadata = vi.fn(); await processReply({ @@ -175,7 +175,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid1", xmtpID: "testXmtpId1", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const originalMessageFromReply = await getOriginalMessageFromReply( testTextMessage, @@ -201,7 +201,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid2", xmtpID: "testXmtpId2", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const originalMessageFromReply2 = await getOriginalMessageFromReply( testReplyMessage, @@ -227,7 +227,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid1", xmtpID: "testXmtpId1", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const replies = await getReplies(testTextMessage, db); expect(replies).toEqual([]); @@ -250,7 +250,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid1", xmtpID: "testXmtpId1", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const testReplyMessage1 = { id: 2, @@ -270,7 +270,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid2", xmtpID: "testXmtpId2", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await saveMessage(testReplyMessage1, db); @@ -292,7 +292,7 @@ describe("ContentTypeReply", () => { senderAddress: "testWalletAddress", uuid: "testUuid3", xmtpID: "testXmtpId3", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; await saveMessage(testReplyMessage2, db); diff --git a/packages/react-sdk/src/helpers/caching/contentTypes/reply.ts b/packages/react-sdk/src/helpers/caching/contentTypes/reply.ts index d3247c4a..e5398b05 100644 --- a/packages/react-sdk/src/helpers/caching/contentTypes/reply.ts +++ b/packages/react-sdk/src/helpers/caching/contentTypes/reply.ts @@ -5,7 +5,6 @@ import { z } from "zod"; import { ContentTypeId } from "@xmtp/content-type-primitives"; import type { CachedMessage, - CachedMessageWithId, CachedMessagesTable, } from "@/helpers/caching/messages"; import type { @@ -75,7 +74,7 @@ export const getReplies = async (message: CachedMessage, db: Dexie) => { .where("xmtpID") .anyOf(replies.map((reply) => reply.xmtpID)) .sortBy("sentAt"); - return replyMessages as CachedMessageWithId[]; + return replyMessages; } return []; }; diff --git a/packages/react-sdk/src/helpers/caching/db.ts b/packages/react-sdk/src/helpers/caching/db.ts index 7a7a87ed..bc132df2 100644 --- a/packages/react-sdk/src/helpers/caching/db.ts +++ b/packages/react-sdk/src/helpers/caching/db.ts @@ -1,7 +1,10 @@ import Dexie from "dexie"; import type { Client } from "@xmtp/xmtp-js"; import type { ContentCodec } from "@xmtp/content-type-primitives"; -import type { CachedMessage } from "@/helpers/caching/messages"; +import type { + CachedMessage, + CachedMessageWithOptionalId, +} from "@/helpers/caching/messages"; import type { CachedConversation } from "./conversations"; import { textContentTypeConfig } from "./contentTypes/text"; @@ -32,7 +35,7 @@ export type ContentTypeMessageProcessor = (options: { client: Client; conversation: CachedConversation; db: Dexie; - message: CachedMessage; + message: CachedMessageWithOptionalId; processors?: ContentTypeMessageProcessors; updateConversationMetadata: ( data: ContentTypeMetadataValues, diff --git a/packages/react-sdk/src/helpers/caching/messages.test.ts b/packages/react-sdk/src/helpers/caching/messages.test.ts index dcf1b962..1915e560 100644 --- a/packages/react-sdk/src/helpers/caching/messages.test.ts +++ b/packages/react-sdk/src/helpers/caching/messages.test.ts @@ -126,6 +126,7 @@ describe("saveMessage", () => { it("should return a duplicate message", async () => { const testMessage = { + id: 1, walletAddress: "testWalletAddress", conversationTopic: "testTopic", content: "test", diff --git a/packages/react-sdk/src/helpers/caching/messages.ts b/packages/react-sdk/src/helpers/caching/messages.ts index c01d9555..faff88bf 100644 --- a/packages/react-sdk/src/helpers/caching/messages.ts +++ b/packages/react-sdk/src/helpers/caching/messages.ts @@ -32,7 +32,7 @@ export type CachedMessage = { conversationTopic: string; hasLoadError: boolean; hasSendError: boolean; - id?: number; + id: number; isSending: boolean; metadata?: M; senderAddress: string; @@ -44,12 +44,19 @@ export type CachedMessage = { xmtpID: string; }; -export type CachedMessagesTable = Table; - -export type CachedMessageWithId = CachedMessage & { - id: number; +export type CachedMessageWithOptionalId = Omit< + CachedMessage, + "id" +> & { + id?: CachedMessage["id"]; }; +export type CachedMessagesTable = Table< + CachedMessage, + number, + Omit, "id"> +>; + /** * Converts a DecodedMessage from the XMTP network to its cached format * @@ -83,7 +90,7 @@ export const toCachedMessage = ( uuid: v4(), walletAddress, xmtpID: message.id, - } satisfies CachedMessage; + } satisfies Omit; }; /** @@ -96,7 +103,7 @@ export const toCachedMessage = ( export const getMessageByXmtpID = async (xmtpID: string, db: Dexie) => { const messages = db.table("messages") as CachedMessagesTable; const message = await messages.where("xmtpID").equals(xmtpID).first(); - return message ? (message as CachedMessageWithId) : undefined; + return message; }; export type SaveMessageOptions = Omit< @@ -109,7 +116,10 @@ export type SaveMessageOptions = Omit< * * @returns The newly cached message, or an already existing cached message */ -export const saveMessage = async (message: CachedMessage, db: Dexie) => { +export const saveMessage = async ( + message: Omit, + db: Dexie, +) => { const messages = db.table("messages") as CachedMessagesTable; // check if message already exists @@ -117,7 +127,7 @@ export const saveMessage = async (message: CachedMessage, db: Dexie) => { if (existing) { // return the existing message - return existing as CachedMessageWithId; + return existing; } const id = await messages.add(message); @@ -131,10 +141,7 @@ export const saveMessage = async (message: CachedMessage, db: Dexie) => { /** * Remove a message from the cache */ -export const deleteMessage = async ( - message: CachedMessageWithId, - db: Dexie, -) => { +export const deleteMessage = async (message: CachedMessage, db: Dexie) => { const messagesTable = db.table("messages") as CachedMessagesTable; // make sure message exists @@ -208,7 +215,7 @@ export const prepareMessageForSending = async ({ conversation, sendOptions, }: PrepareMessageOptions): Promise<{ - message: CachedMessage; + message: Omit; preparedMessage: Awaited>; }> => { const networkConversation = await getConversationByTopic( @@ -244,7 +251,7 @@ export const prepareMessageForSending = async ({ uuid: v4(), walletAddress: client.address, xmtpID: await preparedMessage.messageID(), - } satisfies CachedMessage; + } satisfies Omit; return { message, @@ -275,7 +282,7 @@ export type ProcessMessageOptions = { client?: Client; conversation: CachedConversation; db: Dexie; - message: CachedMessage; + message: CachedMessageWithOptionalId; namespaces: Record; processors: ContentTypeMessageProcessors; validators: ContentTypeMessageValidators; @@ -322,7 +329,7 @@ export const processMessage = async ( removeExisting = false, ): Promise<{ status: ProcessStatus; - message: CachedMessage; + message: CachedMessageWithOptionalId; }> => { // client is required if (!client) { diff --git a/packages/react-sdk/src/hooks/useMessage.ts b/packages/react-sdk/src/hooks/useMessage.ts index abe16f4d..94d0e4b8 100644 --- a/packages/react-sdk/src/hooks/useMessage.ts +++ b/packages/react-sdk/src/hooks/useMessage.ts @@ -13,7 +13,7 @@ import { } from "@/helpers/caching/messages"; import type { CachedMessage, - CachedMessageWithId, + ProcessMessageOptions, } from "@/helpers/caching/messages"; import { getConversationByTopic, @@ -39,7 +39,10 @@ export const useMessage = () => { const { db } = useDb(); const processMessage = useCallback( - async (conversation: CachedConversation, message: CachedMessage) => + async ( + conversation: ProcessMessageOptions["conversation"], + message: ProcessMessageOptions["message"], + ) => _processMessage({ client, conversation, @@ -145,7 +148,10 @@ export const useMessage = () => { // before updating, make sure the message was added to cache if (message.id) { - await updateMessageAfterSending(message, sentMessage.sent); + await updateMessageAfterSending( + message as CachedMessage, + sentMessage.sent, + ); } return { @@ -155,7 +161,7 @@ export const useMessage = () => { } catch (e) { // before updating, make sure the message is in the cache if (message.id) { - await updateMessage(message, { + await updateMessage(message as CachedMessage, { hasSendError: true, sendOptions: finalSendOptions, }); @@ -185,7 +191,7 @@ export const useMessage = () => { * @returns The sent message, or `undefined` if there's no XMTP client */ const resendMessage = useCallback( - async (message: CachedMessageWithId) => { + async (message: CachedMessage) => { if (!message.hasSendError) { throw new Error( "Resending a message that hasn't failed to send is not allowed", diff --git a/packages/react-sdk/src/hooks/useMessages.ts b/packages/react-sdk/src/hooks/useMessages.ts index f2f3707b..e9a3fd91 100644 --- a/packages/react-sdk/src/hooks/useMessages.ts +++ b/packages/react-sdk/src/hooks/useMessages.ts @@ -3,7 +3,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { min, subSeconds } from "date-fns"; import type { OnError } from "../sharedTypes"; import { useCachedMessages } from "./useCachedMessages"; -import type { CachedMessageWithId } from "@/helpers/caching/messages"; import { toCachedMessage } from "@/helpers/caching/messages"; import { getConversationByTopic } from "@/helpers/caching/conversations"; import type { CachedConversation } from "@/helpers/caching/conversations"; @@ -37,9 +36,7 @@ export const useMessages = ( const [error, setError] = useState(null); const { processMessage } = useMessage(); const { updateConversation } = useConversationInternal(); - const messages = useCachedMessages( - conversation.topic, - ) as CachedMessageWithId[]; + const messages = useCachedMessages(conversation.topic); const { client } = useClient(); // to prevent messages from being fetched multiple times const loadingRef = useRef(false); diff --git a/packages/react-sdk/src/hooks/useResendMessage.test.ts b/packages/react-sdk/src/hooks/useResendMessage.test.ts index 40c5ef77..6ab1836a 100644 --- a/packages/react-sdk/src/hooks/useResendMessage.test.ts +++ b/packages/react-sdk/src/hooks/useResendMessage.test.ts @@ -2,7 +2,7 @@ import { it, expect, describe, vi, beforeEach } from "vitest"; import { act, renderHook, waitFor } from "@testing-library/react"; import { ContentTypeText } from "@xmtp/content-type-text"; import { useResendMessage } from "@/hooks/useResendMessage"; -import type { CachedMessageWithId } from "@/helpers/caching/messages"; +import type { CachedMessage } from "@/helpers/caching/messages"; const resendMock = vi.hoisted(() => vi.fn()); @@ -39,7 +39,7 @@ describe("useResendMessage", () => { uuid: "testUuid", walletAddress: "testWalletAddress", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const { result } = renderHook(() => useResendMessage({ @@ -77,7 +77,7 @@ describe("useResendMessage", () => { uuid: "testUuid", walletAddress: "testWalletAddress", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; const { result } = renderHook(() => useResendMessage({ diff --git a/packages/react-sdk/src/hooks/useResendMessage.ts b/packages/react-sdk/src/hooks/useResendMessage.ts index 65189dd9..c1ec74dc 100644 --- a/packages/react-sdk/src/hooks/useResendMessage.ts +++ b/packages/react-sdk/src/hooks/useResendMessage.ts @@ -1,7 +1,7 @@ import { useCallback, useState } from "react"; import { useMessage } from "@/hooks/useMessage"; import type { UseSendMessageOptions } from "@/hooks/useSendMessage"; -import type { CachedMessageWithId } from "@/helpers/caching/messages"; +import type { CachedMessage } from "@/helpers/caching/messages"; /** * This hook can be used to resend a previously failed message, or cancel it. @@ -15,7 +15,7 @@ export const useResendMessage = (options?: UseSendMessageOptions) => { const { onError, onSuccess } = options ?? {}; const resend = useCallback( - async (message: CachedMessageWithId) => { + async (message: CachedMessage) => { setIsLoading(true); setError(null); @@ -36,7 +36,7 @@ export const useResendMessage = (options?: UseSendMessageOptions) => { ); const cancel = useCallback( - async (message: CachedMessageWithId) => { + async (message: CachedMessage) => { try { await deleteMessage(message); } catch (e) { diff --git a/packages/react-sdk/src/hooks/useStartConversation.test.ts b/packages/react-sdk/src/hooks/useStartConversation.test.ts index 09bc5f8c..a320a900 100644 --- a/packages/react-sdk/src/hooks/useStartConversation.test.ts +++ b/packages/react-sdk/src/hooks/useStartConversation.test.ts @@ -7,7 +7,7 @@ import { toCachedConversation, type CachedConversation, } from "@/helpers/caching/conversations"; -import type { CachedMessageWithId } from "@/helpers/caching/messages"; +import type { CachedMessage } from "@/helpers/caching/messages"; const useClientMock = vi.hoisted(() => vi.fn()); const sendMessageMock = vi.hoisted(() => vi.fn()); @@ -255,7 +255,7 @@ describe("useStartConversation", () => { walletAddress: "testWalletAddress", uuid: "testUuid", xmtpID: "testXmtpId", - } satisfies CachedMessageWithId; + } satisfies CachedMessage; saveConversationMock.mockResolvedValueOnce(savedConversation); sendMessageMock.mockResolvedValueOnce({ cachedMessage: savedMessage, diff --git a/packages/react-sdk/src/index.ts b/packages/react-sdk/src/index.ts index f19b52a8..fd336fb7 100644 --- a/packages/react-sdk/src/index.ts +++ b/packages/react-sdk/src/index.ts @@ -42,7 +42,6 @@ export { useStreamMessages } from "./hooks/useStreamMessages"; export type { CachedMessage, - CachedMessageWithId, CachedMessagesTable, ProcessUnprocessedMessagesOptions, } from "./helpers/caching/messages";