@planningcenter/chat-react-native 3.45.1-qa-staging.5 → 3.45.1-qa-staging.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/build/components/conversation/message.d.ts.map +1 -1
  2. package/build/components/conversation/message.js +8 -7
  3. package/build/components/conversation/message.js.map +1 -1
  4. package/build/components/conversation/reply_shadow_message.d.ts +1 -1
  5. package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
  6. package/build/components/conversation/reply_shadow_message.js +44 -43
  7. package/build/components/conversation/reply_shadow_message.js.map +1 -1
  8. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  9. package/build/hooks/use_conversation_messages_jolt_events.js +6 -1
  10. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  11. package/build/hooks/use_message_create_or_update.d.ts +99 -4
  12. package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
  13. package/build/hooks/use_message_create_or_update.js +47 -6
  14. package/build/hooks/use_message_create_or_update.js.map +1 -1
  15. package/build/types/resources/message.d.ts +2 -0
  16. package/build/types/resources/message.d.ts.map +1 -1
  17. package/build/types/resources/message.js.map +1 -1
  18. package/build/utils/cache/messages_cache.d.ts +1 -0
  19. package/build/utils/cache/messages_cache.d.ts.map +1 -1
  20. package/build/utils/cache/messages_cache.js +14 -7
  21. package/build/utils/cache/messages_cache.js.map +1 -1
  22. package/build/utils/cache/optimistically_create_message.d.ts +2 -1
  23. package/build/utils/cache/optimistically_create_message.d.ts.map +1 -1
  24. package/build/utils/cache/optimistically_create_message.js +4 -2
  25. package/build/utils/cache/optimistically_create_message.js.map +1 -1
  26. package/build/utils/client/transform_response.d.ts.map +1 -1
  27. package/build/utils/client/transform_response.js +9 -5
  28. package/build/utils/client/transform_response.js.map +1 -1
  29. package/build/utils/group_messages.d.ts +1 -0
  30. package/build/utils/group_messages.d.ts.map +1 -1
  31. package/build/utils/group_messages.js +10 -1
  32. package/build/utils/group_messages.js.map +1 -1
  33. package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts.map +1 -1
  34. package/build/utils/jolt/transform_message_event_data_to_message_resource.js +1 -0
  35. package/build/utils/jolt/transform_message_event_data_to_message_resource.js.map +1 -1
  36. package/build/utils/request/messages_data_options.d.ts.map +1 -1
  37. package/build/utils/request/messages_data_options.js +2 -2
  38. package/build/utils/request/messages_data_options.js.map +1 -1
  39. package/package.json +3 -3
  40. package/src/components/conversation/__tests__/reply_shadow_message.test.tsx +119 -0
  41. package/src/components/conversation/message.tsx +8 -7
  42. package/src/components/conversation/reply_shadow_message.tsx +6 -4
  43. package/src/hooks/__tests__/use_message_create_or_update.test.tsx +110 -0
  44. package/src/hooks/use_conversation_messages_jolt_events.ts +7 -0
  45. package/src/hooks/use_message_create_or_update.ts +29 -16
  46. package/src/types/resources/message.ts +2 -0
  47. package/src/utils/__tests__/group_messages.test.ts +48 -0
  48. package/src/utils/cache/__tests__/messages_cache.test.ts +89 -0
  49. package/src/utils/cache/__tests__/messages_cache_reply_roots.test.ts +71 -0
  50. package/src/utils/cache/messages_cache.ts +27 -11
  51. package/src/utils/cache/optimistically_create_message.ts +3 -0
  52. package/src/utils/client/__tests__/transform_response.test.ts +62 -0
  53. package/src/utils/client/transform_response.ts +7 -5
  54. package/src/utils/group_messages.ts +18 -1
  55. package/src/utils/jolt/transform_message_event_data_to_message_resource.ts +1 -0
  56. package/src/utils/request/messages_data_options.ts +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages_jolt_events.js","names":["useQueryClient","deleteRecordInPagesData","updateCacheWithMessage","updateCacheWithIndividualMessage","updateCacheWithReaction","getThreadedMessagesQueryKey","transformMessageEventDataToMessageResource","completeMessageCreationTracking","getMessageQueryKey","getMessagesRequestArgs","useApiClient","useCurrentPerson","useJoltChannel","useJoltEvent","getRequestQueryKey","TYPING_TIMEOUT_INTERVAL","useTypingStatusCache","useConversationMessagesJoltEvents","t0","$","_c","conversationId","queryClient","currentPerson","joltChannel","t1","messagesRequestArgs","conversation_id","messagesQueryKey","apiClient","addTypingEvent","removeTypingEventById","removeAllTypingEventsByAuthorId","t2","id","e","data","message","currentPersonId","event","author_id","idempotent_key","idempotentKey","reply_root_id","threadedMessagesQueryKey","individualMessageQueryKey","messageId","sort_key","handleMessageUpdateOrCreate","t3","e_0","data_0","message_0","setQueryData","prev","record","threadedMessagesQueryKey_0","prev_0","handleMessageDeleted","t4","e_1","replyRootId","threadedMessagesQueryKey_1","handleReactionJoltEvent","t5","e_2","data_1","setTimeout","handleTypingEvent"],"sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"sourcesContent":["import { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { ApiCollection, MessageResource } from '../types'\nimport { JoltReactionEvent, JoltTypingEvent } from '../types/jolt_events'\nimport {\n MessageCreatedEvent,\n MessageUpdatedEvent,\n MessageDeletedEvent,\n} from '../types/jolt_events/message_events'\nimport { deleteRecordInPagesData } from '../utils'\nimport {\n updateCacheWithMessage,\n updateCacheWithIndividualMessage,\n updateCacheWithReaction,\n getThreadedMessagesQueryKey,\n} from '../utils/cache/messages_cache'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { completeMessageCreationTracking } from '../utils/performance_tracking'\nimport { getMessageQueryKey } from '../utils/request/get_message'\nimport { getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { useCurrentPerson } from './use_current_person'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { getRequestQueryKey } from './use_suspense_api'\nimport { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache'\n\ninterface Props {\n conversationId: number\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n const apiClient = useApiClient()\n\n const { addTypingEvent, removeTypingEventById, removeAllTypingEventsByAuthorId } =\n useTypingStatusCache(conversationId)\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent | MessageUpdatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n if (e.event === 'message.created' && data.author_id) {\n removeAllTypingEventsByAuthorId(data.author_id)\n if (data.idempotent_key && data.author_id === currentPerson.id) {\n completeMessageCreationTracking({ apiClient, idempotentKey: data.idempotent_key })\n }\n }\n\n // Update the main conversation cache\n updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event)\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event)\n }\n\n // Update individual message query cache so reply shadow messages update immediately\n if (e.event === 'message.updated') {\n const individualMessageQueryKey = getMessageQueryKey({\n conversation_id: conversationId,\n messageId: data.sort_key,\n })\n updateCacheWithIndividualMessage(queryClient, individualMessageQueryKey, message)\n }\n }\n\n const handleMessageDeleted = async (e: MessageDeletedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n // Update the main conversation cache\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n queryClient.setQueryData<QueryData>(threadedMessagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n }\n }\n\n const handleReactionJoltEvent = async (e: JoltReactionEvent) => {\n // Update the main conversation cache and capture the reply_root_id if present\n updateCacheWithReaction(queryClient, messagesQueryKey, e, currentPerson.id)\n\n const replyRootId = e.data.data.reply_root_id\n\n // If the message has a reply_root_id, also update the threaded cache\n if (replyRootId) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, replyRootId)\n updateCacheWithReaction(queryClient, threadedMessagesQueryKey, e, currentPerson.id)\n }\n }\n\n const handleTypingEvent = async (e: JoltTypingEvent) => {\n const { data } = e.data\n addTypingEvent(data)\n setTimeout(() => removeTypingEventById(data.id), TYPING_TIMEOUT_INTERVAL)\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n useJoltEvent(joltChannel, 'typing.broadcast', handleTypingEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"use_conversation_messages_jolt_events.js","names":["useQueryClient","deleteRecordInPagesData","updateCacheWithMessage","updateCacheWithIndividualMessage","updateCacheWithReaction","updateCacheReplyRoots","getThreadedMessagesQueryKey","transformMessageEventDataToMessageResource","completeMessageCreationTracking","getMessageQueryKey","getMessagesRequestArgs","useApiClient","useCurrentPerson","useJoltChannel","useJoltEvent","getRequestQueryKey","TYPING_TIMEOUT_INTERVAL","useTypingStatusCache","useConversationMessagesJoltEvents","t0","$","_c","conversationId","queryClient","currentPerson","joltChannel","t1","messagesRequestArgs","conversation_id","messagesQueryKey","apiClient","addTypingEvent","removeTypingEventById","removeAllTypingEventsByAuthorId","t2","id","e","data","message","currentPersonId","isReplyRootUpdate","event","reply_root_id","sort_key","author_id","idempotent_key","idempotentKey","threadedMessagesQueryKey","individualMessageQueryKey","messageId","handleMessageUpdateOrCreate","t3","e_0","data_0","message_0","setQueryData","prev","record","threadedMessagesQueryKey_0","prev_0","handleMessageDeleted","t4","e_1","replyRootId","threadedMessagesQueryKey_1","handleReactionJoltEvent","t5","e_2","data_1","setTimeout","handleTypingEvent"],"sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"sourcesContent":["import { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { ApiCollection, MessageResource } from '../types'\nimport { JoltReactionEvent, JoltTypingEvent } from '../types/jolt_events'\nimport {\n MessageCreatedEvent,\n MessageUpdatedEvent,\n MessageDeletedEvent,\n} from '../types/jolt_events/message_events'\nimport { deleteRecordInPagesData } from '../utils'\nimport {\n updateCacheWithMessage,\n updateCacheWithIndividualMessage,\n updateCacheWithReaction,\n updateCacheReplyRoots,\n getThreadedMessagesQueryKey,\n} from '../utils/cache/messages_cache'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { completeMessageCreationTracking } from '../utils/performance_tracking'\nimport { getMessageQueryKey } from '../utils/request/get_message'\nimport { getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { useCurrentPerson } from './use_current_person'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { getRequestQueryKey } from './use_suspense_api'\nimport { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache'\n\ninterface Props {\n conversationId: number\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n const apiClient = useApiClient()\n\n const { addTypingEvent, removeTypingEventById, removeAllTypingEventsByAuthorId } =\n useTypingStatusCache(conversationId)\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent | MessageUpdatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n const isReplyRootUpdate = e.event === 'message.updated' && data.reply_root_id === data.sort_key\n\n if (e.event === 'message.created' && data.author_id) {\n removeAllTypingEventsByAuthorId(data.author_id)\n if (data.idempotent_key && data.author_id === currentPerson.id) {\n completeMessageCreationTracking({ apiClient, idempotentKey: data.idempotent_key })\n }\n }\n\n // Update the main conversation cache\n updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event)\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event)\n\n if (isReplyRootUpdate) {\n updateCacheReplyRoots(queryClient, messagesQueryKey, message)\n updateCacheReplyRoots(queryClient, threadedMessagesQueryKey, message)\n }\n }\n\n // Update individual message query cache so reply shadow messages update immediately\n if (e.event === 'message.updated') {\n const individualMessageQueryKey = getMessageQueryKey({\n conversation_id: conversationId,\n messageId: data.sort_key,\n })\n updateCacheWithIndividualMessage(queryClient, individualMessageQueryKey, message)\n }\n }\n\n const handleMessageDeleted = async (e: MessageDeletedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n // Update the main conversation cache\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n queryClient.setQueryData<QueryData>(threadedMessagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n }\n }\n\n const handleReactionJoltEvent = async (e: JoltReactionEvent) => {\n // Update the main conversation cache and capture the reply_root_id if present\n updateCacheWithReaction(queryClient, messagesQueryKey, e, currentPerson.id)\n\n const replyRootId = e.data.data.reply_root_id\n\n // If the message has a reply_root_id, also update the threaded cache\n if (replyRootId) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, replyRootId)\n updateCacheWithReaction(queryClient, threadedMessagesQueryKey, e, currentPerson.id)\n }\n }\n\n const handleTypingEvent = async (e: JoltTypingEvent) => {\n const { data } = e.data\n addTypingEvent(data)\n setTimeout(() => removeTypingEventById(data.id), TYPING_TIMEOUT_INTERVAL)\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n useJoltEvent(joltChannel, 'typing.broadcast', handleTypingEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"],"mappings":"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","ignoreList":[]}
@@ -5,11 +5,106 @@ interface Props {
5
5
  message?: MessageResource;
6
6
  replyRootId?: string | null;
7
7
  }
8
- export declare function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props): import("@tanstack/react-query").UseMutationResult<ApiResource<MessageResource>, Error, {
8
+ interface MessageMutationVariables {
9
9
  text: string;
10
10
  attachments?: DenormalizedAttachmentResourceForCreate[];
11
- }, {
12
- message: MessageResource;
13
- }>;
11
+ idempotentKey?: string;
12
+ }
13
+ type ResolvedMessageMutationVariables = MessageMutationVariables & {
14
+ idempotentKey: string;
15
+ };
16
+ export declare function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props): {
17
+ mutate: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
18
+ message: MessageResource;
19
+ }>>[1]) => void;
20
+ mutateAsync: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateAsyncFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
21
+ message: MessageResource;
22
+ }>>[1]) => Promise<ApiResource<MessageResource>>;
23
+ data: undefined;
24
+ variables: undefined;
25
+ error: null;
26
+ isError: false;
27
+ isIdle: true;
28
+ isPending: false;
29
+ isSuccess: false;
30
+ status: "idle";
31
+ reset: () => void;
32
+ context: {
33
+ message: MessageResource;
34
+ } | undefined;
35
+ failureCount: number;
36
+ failureReason: Error | null;
37
+ isPaused: boolean;
38
+ submittedAt: number;
39
+ } | {
40
+ mutate: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
41
+ message: MessageResource;
42
+ }>>[1]) => void;
43
+ mutateAsync: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateAsyncFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
44
+ message: MessageResource;
45
+ }>>[1]) => Promise<ApiResource<MessageResource>>;
46
+ data: undefined;
47
+ variables: ResolvedMessageMutationVariables;
48
+ error: null;
49
+ isError: false;
50
+ isIdle: false;
51
+ isPending: true;
52
+ isSuccess: false;
53
+ status: "pending";
54
+ reset: () => void;
55
+ context: {
56
+ message: MessageResource;
57
+ } | undefined;
58
+ failureCount: number;
59
+ failureReason: Error | null;
60
+ isPaused: boolean;
61
+ submittedAt: number;
62
+ } | {
63
+ mutate: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
64
+ message: MessageResource;
65
+ }>>[1]) => void;
66
+ mutateAsync: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateAsyncFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
67
+ message: MessageResource;
68
+ }>>[1]) => Promise<ApiResource<MessageResource>>;
69
+ data: undefined;
70
+ error: Error;
71
+ variables: ResolvedMessageMutationVariables;
72
+ isError: true;
73
+ isIdle: false;
74
+ isPending: false;
75
+ isSuccess: false;
76
+ status: "error";
77
+ reset: () => void;
78
+ context: {
79
+ message: MessageResource;
80
+ } | undefined;
81
+ failureCount: number;
82
+ failureReason: Error | null;
83
+ isPaused: boolean;
84
+ submittedAt: number;
85
+ } | {
86
+ mutate: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
87
+ message: MessageResource;
88
+ }>>[1]) => void;
89
+ mutateAsync: (variables: MessageMutationVariables, options?: Parameters<import("@tanstack/react-query").UseMutateAsyncFunction<ApiResource<MessageResource>, Error, ResolvedMessageMutationVariables, {
90
+ message: MessageResource;
91
+ }>>[1]) => Promise<ApiResource<MessageResource>>;
92
+ data: ApiResource<MessageResource>;
93
+ error: null;
94
+ variables: ResolvedMessageMutationVariables;
95
+ isError: false;
96
+ isIdle: false;
97
+ isPending: false;
98
+ isSuccess: true;
99
+ status: "success";
100
+ reset: () => void;
101
+ context: {
102
+ message: MessageResource;
103
+ } | undefined;
104
+ failureCount: number;
105
+ failureReason: Error | null;
106
+ isPaused: boolean;
107
+ submittedAt: number;
108
+ };
14
109
  export {};
15
110
  //# sourceMappingURL=use_message_create_or_update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_message_create_or_update.d.ts","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AACtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,gEAAgE,CAAA;AAexH,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK;UAqD5E,MAAM;kBACE,uCAAuC,EAAE;;;GAgF5D"}
1
+ {"version":3,"file":"use_message_create_or_update.d.ts","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AACtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,gEAAgE,CAAA;AAexH,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,UAAU,wBAAwB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,uCAAuC,EAAE,CAAA;IACvD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,KAAK,gCAAgC,GAAG,wBAAwB,GAAG;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5F,wBAAgB,wBAAwB,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK;wBAiIzE,wBAAwB,YACzB,UAAU;;OAAwB,CAAC,CAAC,CAAC;6BAIpC,wBAAwB,YACzB,UAAU;;OAA6B,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;wBANzC,wBAAwB,YACzB,UAAU;;OAAwB,CAAC,CAAC,CAAC;6BAIpC,wBAAwB,YACzB,UAAU;;OAA6B,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;wBANzC,wBAAwB,YACzB,UAAU;;OAAwB,CAAC,CAAC,CAAC;6BAIpC,wBAAwB,YACzB,UAAU;;OAA6B,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;wBANzC,wBAAwB,YACzB,UAAU;;OAAwB,CAAC,CAAC,CAAC;6BAIpC,wBAAwB,YACzB,UAAU;;OAA6B,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;EAIvD"}
@@ -10,7 +10,7 @@ import { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/ge
10
10
  import { useApiClient } from './use_api_client';
11
11
  import { useCurrentPerson } from './use_current_person';
12
12
  export function useMessageCreateOrUpdate(t0) {
13
- const $ = _c(23);
13
+ const $ = _c(33);
14
14
  const {
15
15
  conversationId,
16
16
  message,
@@ -33,7 +33,8 @@ export function useMessageCreateOrUpdate(t0) {
33
33
  t2 = t3 => {
34
34
  const {
35
35
  text,
36
- attachments
36
+ attachments,
37
+ idempotentKey
37
38
  } = t3;
38
39
  const requestParams = getMessagesRequestArgs({
39
40
  conversation_id: conversationId
@@ -51,7 +52,6 @@ export function useMessageCreateOrUpdate(t0) {
51
52
  } : {})
52
53
  };
53
54
  if (!isEditing) {
54
- const idempotentKey = insecureUUID();
55
55
  attributes.idempotent_key = idempotentKey;
56
56
  startMessageCreationTracking(idempotentKey);
57
57
  }
@@ -89,7 +89,8 @@ export function useMessageCreateOrUpdate(t0) {
89
89
  t3 = async t4 => {
90
90
  const {
91
91
  text: text_0,
92
- attachments: attachments_0
92
+ attachments: attachments_0,
93
+ idempotentKey: idempotentKey_0
93
94
  } = t4;
94
95
  if (message && isEditing) {
95
96
  const optimisticMessage = optimisticallyUpdateMessage({
@@ -108,7 +109,8 @@ export function useMessageCreateOrUpdate(t0) {
108
109
  text: text_0,
109
110
  attachments: attachments_0,
110
111
  currentPerson,
111
- replyRootId
112
+ replyRootId,
113
+ idempotentKey: idempotentKey_0
112
114
  });
113
115
  return {
114
116
  message: optimisticMessage_0
@@ -193,7 +195,46 @@ export function useMessageCreateOrUpdate(t0) {
193
195
  t6 = $[22];
194
196
  }
195
197
  const mutation = useMutation(t6);
196
- return mutation;
198
+ let t7;
199
+ if ($[23] !== message?.idempotentKey) {
200
+ t7 = variables_1 => ({
201
+ ...variables_1,
202
+ idempotentKey: variables_1.idempotentKey ?? message?.idempotentKey ?? insecureUUID()
203
+ });
204
+ $[23] = message?.idempotentKey;
205
+ $[24] = t7;
206
+ } else {
207
+ t7 = $[24];
208
+ }
209
+ const resolveVariables = t7;
210
+ let mutate;
211
+ let mutateAsync;
212
+ if ($[25] !== mutation || $[26] !== resolveVariables) {
213
+ mutate = (variables_2, options) => mutation.mutate(resolveVariables(variables_2), options);
214
+ mutateAsync = (variables_3, options_0) => mutation.mutateAsync(resolveVariables(variables_3), options_0);
215
+ $[25] = mutation;
216
+ $[26] = resolveVariables;
217
+ $[27] = mutate;
218
+ $[28] = mutateAsync;
219
+ } else {
220
+ mutate = $[27];
221
+ mutateAsync = $[28];
222
+ }
223
+ let t8;
224
+ if ($[29] !== mutate || $[30] !== mutateAsync || $[31] !== mutation) {
225
+ t8 = {
226
+ ...mutation,
227
+ mutate,
228
+ mutateAsync
229
+ };
230
+ $[29] = mutate;
231
+ $[30] = mutateAsync;
232
+ $[31] = mutation;
233
+ $[32] = t8;
234
+ } else {
235
+ t8 = $[32];
236
+ }
237
+ return t8;
197
238
  }
198
239
 
199
240
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"use_message_create_or_update.js","names":["useMutation","chatQueryClient","deleteRecordInPagesData","Haptic","updateOrCreateRecordInPagesData","updateRecordInPagesData","isNewMessage","mergeMessageUpdate","optimisticallyCreateMessage","optimisticallyUpdateMessage","startMessageCreationTracking","getMessagesQueryKey","getMessagesRequestArgs","useApiClient","useCurrentPerson","useMessageCreateOrUpdate","t0","$","_c","conversationId","message","replyRootId","messageId","id","t1","isEditing","apiClient","currentPerson","t2","t3","text","attachments","requestParams","conversation_id","fieldsWithValueJoined","Object","fromEntries","entries","data","fields","map","_temp","attributes","reply_root","idempotentKey","insecureUUID","idempotent_key","type","chat","patch","url","post","t4","text_0","attachments_0","optimisticMessage","optimisticMessage_0","t5","error","variables","context","optimisticMessage_1","notificationError","queryKey","reply_root_id","setQueryData","data_0","record","processRecord","_next","prev","pending","result","variables_0","context_0","optimisticMessage_2","updatedMessage","queryKey_0","data_1","data_2","_temp2","t6","mutationFn","onMutate","onError","onSuccess","mutation","current","k","v","join","replace","Math","floor","random","toString"],"sources":["../../src/hooks/use_message_create_or_update.ts"],"sourcesContent":["import { InfiniteData, useMutation } from '@tanstack/react-query'\nimport { chatQueryClient } from '../contexts/api_provider'\nimport { ApiCollection, ApiResource, MessageResource } from '../types'\nimport { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'\nimport {\n deleteRecordInPagesData,\n Haptic,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { isNewMessage, mergeMessageUpdate } from '../utils/cache/messages_cache'\nimport { optimisticallyCreateMessage } from '../utils/cache/optimistically_create_message'\nimport { optimisticallyUpdateMessage } from '../utils/cache/optimistically_update_message'\nimport { startMessageCreationTracking } from '../utils/performance_tracking'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { useCurrentPerson } from './use_current_person'\n\ninterface Props {\n conversationId: number\n message?: MessageResource\n replyRootId?: string | null\n}\n\nexport function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props) {\n const messageId = message?.id || null\n const isEditing = !isNewMessage(message)\n const apiClient = useApiClient()\n const currentPerson = useCurrentPerson()\n\n const mutation = useMutation({\n mutationFn: ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversationId })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n let attributes: any = {\n text,\n ...(attachments ? { attachments } : {}),\n ...(!isEditing && replyRootId ? { reply_root: { id: replyRootId } } : {}),\n }\n if (!isEditing) {\n const idempotentKey = insecureUUID()\n attributes.idempotent_key = idempotentKey\n startMessageCreationTracking(idempotentKey)\n }\n const data = {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes,\n },\n fields: fieldsWithValueJoined,\n }\n\n if (isEditing) {\n return apiClient.chat.patch<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages/${messageId}`,\n data,\n })\n } else {\n return apiClient.chat.post<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages`,\n data,\n })\n }\n },\n onMutate: async ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n if (message && isEditing) {\n const optimisticMessage = optimisticallyUpdateMessage({\n conversationId,\n message,\n text,\n replyRootId,\n })\n\n return { message: optimisticMessage }\n }\n\n const optimisticMessage = optimisticallyCreateMessage({\n conversationId,\n message,\n text,\n attachments,\n currentPerson,\n replyRootId,\n })\n\n return { message: optimisticMessage }\n },\n onError: (error, variables, context) => {\n const { message: optimisticMessage } = context || {}\n Haptic.notificationError()\n\n // Add error to the optimistic message from the cache on error\n if (optimisticMessage) {\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n chatQueryClient.setQueryData(\n queryKey,\n (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>\n updateRecordInPagesData({\n data,\n record: optimisticMessage,\n processRecord: (_next, prev) => ({\n ...prev,\n error: error.message || 'Failed to send message',\n pending: false, // Mark as no longer pending\n }),\n })\n )\n }\n },\n onSuccess: (result: ApiResource<MessageResource>, variables, context) => {\n const { message: optimisticMessage } = context || {}\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n // First remove the optimistic message if it exists\n if (optimisticMessage) {\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n deleteRecordInPagesData({\n data,\n record: optimisticMessage,\n })\n )\n }\n\n // Then add the real message\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: updatedMessage,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n )\n },\n })\n\n return mutation\n}\n\n/**\n * Generate a random UUID (v4) for idempotent keys.\n * Uses Math.random, which is not cryptographically secure.\n * An actual crypto library requires native dependencies.\n * This is OK for now since idempotent keys are not security-sensitive\n * or need to be guaranteed unique.\n * They are short lived and we use it in combination with the message's creator_id so\n * their impact is scoped only the current user.\n */\nfunction insecureUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-Nxxx-xxxxxxxxxxxx'\n .replace(/x/g, () => Math.floor(Math.random() * 16).toString(16))\n .replace(/N/g, () => (Math.floor(Math.random() * 4) + 8).toString(16))\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"use_message_create_or_update.js","names":["useMutation","chatQueryClient","deleteRecordInPagesData","Haptic","updateOrCreateRecordInPagesData","updateRecordInPagesData","isNewMessage","mergeMessageUpdate","optimisticallyCreateMessage","optimisticallyUpdateMessage","startMessageCreationTracking","getMessagesQueryKey","getMessagesRequestArgs","useApiClient","useCurrentPerson","useMessageCreateOrUpdate","t0","$","_c","conversationId","message","replyRootId","messageId","id","t1","isEditing","apiClient","currentPerson","t2","t3","text","attachments","idempotentKey","requestParams","conversation_id","fieldsWithValueJoined","Object","fromEntries","entries","data","fields","map","_temp","attributes","reply_root","idempotent_key","type","chat","patch","url","post","t4","text_0","attachments_0","idempotentKey_0","optimisticMessage","optimisticMessage_0","t5","error","variables","context","optimisticMessage_1","notificationError","queryKey","reply_root_id","setQueryData","data_0","record","processRecord","_next","prev","pending","result","variables_0","context_0","optimisticMessage_2","updatedMessage","queryKey_0","data_1","data_2","_temp2","t6","mutationFn","onMutate","onError","onSuccess","mutation","t7","variables_1","insecureUUID","resolveVariables","mutate","mutateAsync","variables_2","options","variables_3","options_0","t8","current","k","v","join","replace","Math","floor","random","toString"],"sources":["../../src/hooks/use_message_create_or_update.ts"],"sourcesContent":["import { InfiniteData, useMutation } from '@tanstack/react-query'\nimport { chatQueryClient } from '../contexts/api_provider'\nimport { ApiCollection, ApiResource, MessageResource } from '../types'\nimport { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'\nimport {\n deleteRecordInPagesData,\n Haptic,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { isNewMessage, mergeMessageUpdate } from '../utils/cache/messages_cache'\nimport { optimisticallyCreateMessage } from '../utils/cache/optimistically_create_message'\nimport { optimisticallyUpdateMessage } from '../utils/cache/optimistically_update_message'\nimport { startMessageCreationTracking } from '../utils/performance_tracking'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { useCurrentPerson } from './use_current_person'\n\ninterface Props {\n conversationId: number\n message?: MessageResource\n replyRootId?: string | null\n}\n\ninterface MessageMutationVariables {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n idempotentKey?: string\n}\n\ntype ResolvedMessageMutationVariables = MessageMutationVariables & { idempotentKey: string }\n\nexport function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props) {\n const messageId = message?.id || null\n const isEditing = !isNewMessage(message)\n const apiClient = useApiClient()\n const currentPerson = useCurrentPerson()\n\n const mutation = useMutation({\n mutationFn: ({ text, attachments, idempotentKey }: ResolvedMessageMutationVariables) => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversationId })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n let attributes: any = {\n text,\n ...(attachments ? { attachments } : {}),\n ...(!isEditing && replyRootId ? { reply_root: { id: replyRootId } } : {}),\n }\n if (!isEditing) {\n attributes.idempotent_key = idempotentKey\n startMessageCreationTracking(idempotentKey)\n }\n const data = {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes,\n },\n fields: fieldsWithValueJoined,\n }\n\n if (isEditing) {\n return apiClient.chat.patch<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages/${messageId}`,\n data,\n })\n } else {\n return apiClient.chat.post<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages`,\n data,\n })\n }\n },\n onMutate: async ({ text, attachments, idempotentKey }: ResolvedMessageMutationVariables) => {\n if (message && isEditing) {\n const optimisticMessage = optimisticallyUpdateMessage({\n conversationId,\n message,\n text,\n replyRootId,\n })\n\n return { message: optimisticMessage }\n }\n\n const optimisticMessage = optimisticallyCreateMessage({\n conversationId,\n message,\n text,\n attachments,\n currentPerson,\n replyRootId,\n idempotentKey,\n })\n\n return { message: optimisticMessage }\n },\n onError: (error, variables, context) => {\n const { message: optimisticMessage } = context || {}\n Haptic.notificationError()\n\n // Add error to the optimistic message from the cache on error\n if (optimisticMessage) {\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n chatQueryClient.setQueryData(\n queryKey,\n (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>\n updateRecordInPagesData({\n data,\n record: optimisticMessage,\n processRecord: (_next, prev) => ({\n ...prev,\n error: error.message || 'Failed to send message',\n pending: false, // Mark as no longer pending\n }),\n })\n )\n }\n },\n onSuccess: (result: ApiResource<MessageResource>, variables, context) => {\n const { message: optimisticMessage } = context || {}\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n // First remove the optimistic message if it exists\n if (optimisticMessage) {\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n deleteRecordInPagesData({\n data,\n record: optimisticMessage,\n })\n )\n }\n\n // Then add the real message\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: updatedMessage,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n )\n },\n })\n\n const resolveVariables = (\n variables: MessageMutationVariables\n ): ResolvedMessageMutationVariables => ({\n ...variables,\n idempotentKey: variables.idempotentKey ?? message?.idempotentKey ?? insecureUUID(),\n })\n\n const mutate = (\n variables: MessageMutationVariables,\n options?: Parameters<typeof mutation.mutate>[1]\n ) => mutation.mutate(resolveVariables(variables), options)\n\n const mutateAsync = (\n variables: MessageMutationVariables,\n options?: Parameters<typeof mutation.mutateAsync>[1]\n ) => mutation.mutateAsync(resolveVariables(variables), options)\n\n return { ...mutation, mutate, mutateAsync }\n}\n\n/**\n * Generate a random UUID (v4) for idempotent keys.\n * Uses Math.random, which is not cryptographically secure.\n * An actual crypto library requires native dependencies.\n * This is OK for now since idempotent keys are not security-sensitive\n * or need to be guaranteed unique.\n * They are short lived and we use it in combination with the message's creator_id so\n * their impact is scoped only the current user.\n */\nfunction insecureUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-Nxxx-xxxxxxxxxxxx'\n .replace(/x/g, () => Math.floor(Math.random() * 16).toString(16))\n .replace(/N/g, () => (Math.floor(Math.random() * 4) + 8).toString(16))\n}\n"],"mappings":"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","ignoreList":[]}
@@ -16,6 +16,8 @@ export interface MessageResource {
16
16
  reactionCounts: ReactionCountResource[];
17
17
  replyCount: number;
18
18
  replyRootId?: string | null;
19
+ replyRoot?: MessageResource | null;
20
+ idempotentKey?: string | null;
19
21
  messageType: string;
20
22
  personIdsForSystemEvent?: number[] | null;
21
23
  systemTextParts?: {
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAA;AACnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAA;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,8BAA8B,EAAE,CAAA;IAC7C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAA;IACnB,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACzC,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAGnF,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAA;IACnD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAGlC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,uCAAuC,EAAE,CAAA;CACjE"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/types/resources/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAA;AACnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAA;AACvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,CAAA;IACf,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,OAAO,CAAA;IACb,WAAW,EAAE,8BAA8B,EAAE,CAAA;IAC7C,MAAM,EAAE,cAAc,CAAA;IACtB,cAAc,EAAE,qBAAqB,EAAE,CAAA;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,uBAAuB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACzC,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAGnF,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAA;IACnD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAGlC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,uCAAuC,EAAE,CAAA;CACjE"}
@@ -1 +1 @@
1
- {"version":3,"file":"message.js","names":[],"sources":["../../../src/types/resources/message.ts"],"sourcesContent":["import { DenormalizedAttachmentResource } from './denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from './denormalized_attachment_resource_for_create'\nimport type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string | null\n html: string\n createdAt: string\n deletedAt: string | null\n textEditedAt: string | null\n mine: boolean\n attachments: DenormalizedAttachmentResource[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n replyCount: number\n replyRootId?: string | null\n messageType: string\n personIdsForSystemEvent?: number[] | null\n systemTextParts?: { names: string[]; overflowCount: number; action: string } | null\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n myLatestInConversation?: boolean\n lastInGroup?: boolean\n threadPosition?: 'first' | 'center' | 'last' | null\n prevIsMyReply?: boolean\n nextIsMyReply?: boolean\n nextRendersAuthor?: boolean\n isReplyShadowMessage?: boolean\n nextIsReplyShadowMessage?: boolean\n\n // Properties for mutation state\n pending?: boolean // Indicates if the message is optimistically created and pending server response\n error?: string // Error message if the message failed to send\n attachmentsForCreate?: DenormalizedAttachmentResourceForCreate[]\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"message.js","names":[],"sources":["../../../src/types/resources/message.ts"],"sourcesContent":["import { DenormalizedAttachmentResource } from './denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from './denormalized_attachment_resource_for_create'\nimport type { PersonResource } from './person'\nimport type { ReactionCountResource } from './reaction'\n\nexport interface MessageResource {\n type: 'Message'\n id: string\n text: string | null\n html: string\n createdAt: string\n deletedAt: string | null\n textEditedAt: string | null\n mine: boolean\n attachments: DenormalizedAttachmentResource[]\n author: PersonResource\n reactionCounts: ReactionCountResource[]\n replyCount: number\n replyRootId?: string | null\n replyRoot?: MessageResource | null\n idempotentKey?: string | null\n messageType: string\n personIdsForSystemEvent?: number[] | null\n systemTextParts?: { names: string[]; overflowCount: number; action: string } | null\n\n // Custom Local Properties we set for rendering\n renderAuthor?: boolean\n renderTime?: boolean\n myLatestInConversation?: boolean\n lastInGroup?: boolean\n threadPosition?: 'first' | 'center' | 'last' | null\n prevIsMyReply?: boolean\n nextIsMyReply?: boolean\n nextRendersAuthor?: boolean\n isReplyShadowMessage?: boolean\n nextIsReplyShadowMessage?: boolean\n\n // Properties for mutation state\n pending?: boolean // Indicates if the message is optimistically created and pending server response\n error?: string // Error message if the message failed to send\n attachmentsForCreate?: DenormalizedAttachmentResourceForCreate[]\n}\n"],"mappings":"","ignoreList":[]}
@@ -3,6 +3,7 @@ import { MessageResource } from '../../types';
3
3
  import { JoltReactionEvent } from '../../types/jolt_events';
4
4
  export declare function updateCacheWithMessage(queryClient: QueryClient, queryKey: unknown[], message: MessageResource, event: 'message.created' | 'message.updated'): void;
5
5
  export declare function updateCacheWithIndividualMessage(queryClient: QueryClient, queryKey: unknown[], message: MessageResource): void;
6
+ export declare function updateCacheReplyRoots(queryClient: QueryClient, queryKey: unknown[], root: MessageResource): void;
6
7
  export declare function updateCacheWithReaction(queryClient: QueryClient, queryKey: unknown[], event: JoltReactionEvent, currentPersonId: number): void;
7
8
  export declare function isTemporaryMessageId(messageId?: string | null): boolean;
8
9
  export declare function isNewMessage(message?: MessageResource): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"messages_cache.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEjE,OAAO,EAA8B,eAAe,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAM3D,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,QAkC7C;AAID,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,QAgBzB;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EACxB,eAAe,EAAE,MAAM,QAuCxB;AAGD,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AACD,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAE/D;AAED,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mCAMtF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,eAAe,CAWjB"}
1
+ {"version":3,"file":"messages_cache.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/messages_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEjE,OAAO,EAA8B,eAAe,EAAE,MAAM,aAAa,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAU3D,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,QA8B7C;AAID,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,eAAe,QAgBzB;AAED,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,IAAI,EAAE,eAAe,QAWtB;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EACxB,eAAe,EAAE,MAAM,QAuCxB;AAGD,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AACD,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAE/D;AAED,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mCAMtF;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,eAAe,GACxB,eAAe,CAWjB"}
@@ -1,21 +1,19 @@
1
1
  import { getRequestQueryKey } from '../../hooks/use_suspense_api';
2
2
  import { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource';
3
3
  import { getMessagesRequestArgs } from '../request/get_messages';
4
- import { updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations';
4
+ import { updateAllRecordsInPagesData, updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations';
5
5
  import { deleteRecordInPagesData } from './page_mutations';
6
6
  export function updateCacheWithMessage(queryClient, queryKey, message, event) {
7
7
  queryClient.setQueryData(queryKey, prev => {
8
8
  if (event === 'message.created') {
9
- // Before adding the new message, remove any pending temporary messages
10
- // with matching text to prevent duplicates from race conditions
9
+ // Before adding the new message, remove its pending temporary counterpart.
10
+ // The Jolt echo can arrive before the HTTP response has swapped it out.
11
11
  let dataAfterTempRemoval = prev;
12
- if (prev && message.text && message.mine) {
12
+ if (prev && message.mine && message.idempotentKey) {
13
13
  dataAfterTempRemoval = deleteRecordInPagesData({
14
14
  data: prev,
15
15
  record: message,
16
- matchFn: (existingMessage, _record) => {
17
- return isTemporaryMessageId(existingMessage.id) && existingMessage.text === message.text && existingMessage.mine;
18
- }
16
+ matchFn: existingMessage => isTemporaryMessageId(existingMessage.id) && existingMessage.idempotentKey === message.idempotentKey
19
17
  });
20
18
  }
21
19
  return updateOrCreateRecordInPagesData({
@@ -47,6 +45,15 @@ export function updateCacheWithIndividualMessage(queryClient, queryKey, message)
47
45
  };
48
46
  });
49
47
  }
48
+ export function updateCacheReplyRoots(queryClient, queryKey, root) {
49
+ queryClient.setQueryData(queryKey, prev => updateAllRecordsInPagesData({
50
+ data: prev,
51
+ processRecord: message => message.replyRoot?.id === root.id ? {
52
+ ...message,
53
+ replyRoot: mergeMessageUpdate(root, message.replyRoot)
54
+ } : message
55
+ }));
56
+ }
50
57
  export function updateCacheWithReaction(queryClient, queryKey, event, currentPersonId) {
51
58
  const message = {
52
59
  id: event.data.data.message_sort_key
@@ -1 +1 @@
1
- {"version":3,"file":"messages_cache.js","names":["getRequestQueryKey","transformReactionEventDataToReactionCountResource","getMessagesRequestArgs","updateOrCreateRecordInPagesData","updateRecordInPagesData","deleteRecordInPagesData","updateCacheWithMessage","queryClient","queryKey","message","event","setQueryData","prev","dataAfterTempRemoval","text","mine","data","record","matchFn","existingMessage","_record","isTemporaryMessageId","id","processRecord","current","mergeMessageUpdate","updateCacheWithIndividualMessage","links","meta","updateCacheWithReaction","currentPersonId","message_sort_key","oldMessage","reactionCounts","foundMatch","newReactionCounts","map","reactionCount","value","oldData","newReactionCount","count","messageId","endsWith","isNewMessage","getThreadedMessagesQueryKey","conversationId","replyRootId","requestArgs","conversation_id","reply_root_id"],"sources":["../../../src/utils/cache/messages_cache.ts"],"sourcesContent":["import { InfiniteData, QueryClient } from '@tanstack/react-query'\nimport { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { ApiCollection, ApiResource, MessageResource } from '../../types'\nimport { JoltReactionEvent } from '../../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../request/get_messages'\nimport { updateOrCreateRecordInPagesData, updateRecordInPagesData } from './page_mutations'\nimport { deleteRecordInPagesData } from './page_mutations'\n\nexport function updateCacheWithMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource,\n event: 'message.created' | 'message.updated'\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev => {\n if (event === 'message.created') {\n // Before adding the new message, remove any pending temporary messages\n // with matching text to prevent duplicates from race conditions\n let dataAfterTempRemoval = prev\n if (prev && message.text && message.mine) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: (existingMessage, _record) => {\n return (\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.text === message.text &&\n existingMessage.mine\n )\n },\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n }\n })\n}\n\ntype IndividualMessageQueryData = ApiResource<MessageResource>\n\nexport function updateCacheWithIndividualMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource\n) {\n queryClient.setQueryData<IndividualMessageQueryData>(queryKey, prev => {\n if (!prev) {\n return {\n data: message,\n links: {},\n meta: {},\n }\n }\n\n return {\n ...prev,\n data: mergeMessageUpdate(message, prev.data),\n }\n })\n}\n\nexport function updateCacheWithReaction(\n queryClient: QueryClient,\n queryKey: unknown[],\n event: JoltReactionEvent,\n currentPersonId: number\n) {\n const message = { id: event.data.data.message_sort_key } as MessageResource\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === event.data.data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n oldData: reactionCount,\n event: event.event,\n currentPersonId,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n event: event.event,\n currentPersonId,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n}\n\ntype MessagesQueryData = InfiniteData<ApiCollection<MessageResource>>\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\nexport function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string) {\n const requestArgs = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n return getRequestQueryKey(requestArgs)\n}\n\nexport function mergeMessageUpdate(\n record: MessageResource,\n current?: MessageResource\n): MessageResource {\n if (!current) {\n return record\n }\n\n return {\n ...current,\n ...record,\n // Preserve reactions from cache - they're managed via separate reaction events\n reactionCounts: current.reactionCounts || [],\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"messages_cache.js","names":["getRequestQueryKey","transformReactionEventDataToReactionCountResource","getMessagesRequestArgs","updateAllRecordsInPagesData","updateOrCreateRecordInPagesData","updateRecordInPagesData","deleteRecordInPagesData","updateCacheWithMessage","queryClient","queryKey","message","event","setQueryData","prev","dataAfterTempRemoval","mine","idempotentKey","data","record","matchFn","existingMessage","isTemporaryMessageId","id","processRecord","current","mergeMessageUpdate","updateCacheWithIndividualMessage","links","meta","updateCacheReplyRoots","root","replyRoot","updateCacheWithReaction","currentPersonId","message_sort_key","oldMessage","reactionCounts","foundMatch","newReactionCounts","map","reactionCount","value","oldData","newReactionCount","count","messageId","endsWith","isNewMessage","getThreadedMessagesQueryKey","conversationId","replyRootId","requestArgs","conversation_id","reply_root_id"],"sources":["../../../src/utils/cache/messages_cache.ts"],"sourcesContent":["import { InfiniteData, QueryClient } from '@tanstack/react-query'\nimport { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { ApiCollection, ApiResource, MessageResource } from '../../types'\nimport { JoltReactionEvent } from '../../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../request/get_messages'\nimport {\n updateAllRecordsInPagesData,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from './page_mutations'\nimport { deleteRecordInPagesData } from './page_mutations'\n\nexport function updateCacheWithMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource,\n event: 'message.created' | 'message.updated'\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev => {\n if (event === 'message.created') {\n // Before adding the new message, remove its pending temporary counterpart.\n // The Jolt echo can arrive before the HTTP response has swapped it out.\n let dataAfterTempRemoval = prev\n if (prev && message.mine && message.idempotentKey) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: existingMessage =>\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.idempotentKey === message.idempotentKey,\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => mergeMessageUpdate(record, current),\n })\n }\n })\n}\n\ntype IndividualMessageQueryData = ApiResource<MessageResource>\n\nexport function updateCacheWithIndividualMessage(\n queryClient: QueryClient,\n queryKey: unknown[],\n message: MessageResource\n) {\n queryClient.setQueryData<IndividualMessageQueryData>(queryKey, prev => {\n if (!prev) {\n return {\n data: message,\n links: {},\n meta: {},\n }\n }\n\n return {\n ...prev,\n data: mergeMessageUpdate(message, prev.data),\n }\n })\n}\n\nexport function updateCacheReplyRoots(\n queryClient: QueryClient,\n queryKey: unknown[],\n root: MessageResource\n) {\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateAllRecordsInPagesData({\n data: prev,\n processRecord: message =>\n message.replyRoot?.id === root.id\n ? { ...message, replyRoot: mergeMessageUpdate(root, message.replyRoot) }\n : message,\n })\n )\n}\n\nexport function updateCacheWithReaction(\n queryClient: QueryClient,\n queryKey: unknown[],\n event: JoltReactionEvent,\n currentPersonId: number\n) {\n const message = { id: event.data.data.message_sort_key } as MessageResource\n queryClient.setQueryData<MessagesQueryData>(queryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === event.data.data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n oldData: reactionCount,\n event: event.event,\n currentPersonId,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data: event.data.data,\n event: event.event,\n currentPersonId,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n}\n\ntype MessagesQueryData = InfiniteData<ApiCollection<MessageResource>>\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\nexport function getThreadedMessagesQueryKey(conversationId: number, replyRootId: string) {\n const requestArgs = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n return getRequestQueryKey(requestArgs)\n}\n\nexport function mergeMessageUpdate(\n record: MessageResource,\n current?: MessageResource\n): MessageResource {\n if (!current) {\n return record\n }\n\n return {\n ...current,\n ...record,\n // Preserve reactions from cache - they're managed via separate reaction events\n reactionCounts: current.reactionCounts || [],\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,11 +1,12 @@
1
1
  import { CurrentPersonResource, MessageResource } from '../../types';
2
2
  import { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create';
3
- export declare function optimisticallyCreateMessage({ conversationId, text, attachments, currentPerson, message, replyRootId, }: {
3
+ export declare function optimisticallyCreateMessage({ conversationId, text, attachments, currentPerson, message, replyRootId, idempotentKey, }: {
4
4
  conversationId: number;
5
5
  text: string;
6
6
  attachments?: DenormalizedAttachmentResourceForCreate[];
7
7
  currentPerson: CurrentPersonResource;
8
8
  message?: MessageResource;
9
9
  replyRootId?: string | null;
10
+ idempotentKey?: string;
10
11
  }): MessageResource;
11
12
  //# sourceMappingURL=optimistically_create_message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"optimistically_create_message.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/optimistically_create_message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,qBAAqB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,mEAAmE,CAAA;AAM3H,wBAAgB,2BAA2B,CAAC,EAC1C,cAAc,EACd,IAAI,EACJ,WAAW,EACX,aAAa,EACb,OAAO,EACP,WAAW,GACZ,EAAE;IACD,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,uCAAuC,EAAE,CAAA;IACvD,aAAa,EAAE,qBAAqB,CAAA;IACpC,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,mBAgDA"}
1
+ {"version":3,"file":"optimistically_create_message.d.ts","sourceRoot":"","sources":["../../../src/utils/cache/optimistically_create_message.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,qBAAqB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAEnF,OAAO,EAAE,uCAAuC,EAAE,MAAM,mEAAmE,CAAA;AAM3H,wBAAgB,2BAA2B,CAAC,EAC1C,cAAc,EACd,IAAI,EACJ,WAAW,EACX,aAAa,EACb,OAAO,EACP,WAAW,EACX,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,uCAAuC,EAAE,CAAA;IACvD,aAAa,EAAE,qBAAqB,CAAA;IACpC,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,mBAiDA"}
@@ -9,7 +9,8 @@ export function optimisticallyCreateMessage({
9
9
  attachments,
10
10
  currentPerson,
11
11
  message,
12
- replyRootId
12
+ replyRootId,
13
+ idempotentKey
13
14
  }) {
14
15
  const id = message?.id || generateTempMessageId();
15
16
 
@@ -39,7 +40,8 @@ export function optimisticallyCreateMessage({
39
40
  lastInGroup: true,
40
41
  pending: true,
41
42
  replyCount: 0,
42
- replyRootId: replyRootId || null
43
+ replyRootId: replyRootId || null,
44
+ idempotentKey
43
45
  };
44
46
 
45
47
  // Add the optimistic message to the cache
@@ -1 +1 @@
1
- {"version":3,"file":"optimistically_create_message.js","names":["chatQueryClient","getMessagesQueryKey","convertAttachmentsForCreate","generatePlaceholderUlid","updateOrCreateRecordInPagesData","optimisticallyCreateMessage","conversationId","text","attachments","currentPerson","message","replyRootId","id","generateTempMessageId","decoratedAttachments","optimisticMessage","type","messageType","html","createdAt","Date","toISOString","deletedAt","textEditedAt","mine","attachmentsForCreate","author","reactionCounts","renderAuthor","renderTime","myLatestInConversation","lastInGroup","pending","replyCount","queryKey","conversation_id","reply_root_id","setQueryData","data","record","offsetMs"],"sources":["../../../src/utils/cache/optimistically_create_message.ts"],"sourcesContent":["import { InfiniteData } from '@tanstack/react-query'\nimport { chatQueryClient } from '../../contexts/api_provider'\nimport { ApiCollection, CurrentPersonResource, MessageResource } from '../../types'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create'\nimport { getMessagesQueryKey } from '../../utils/request/get_messages'\nimport { convertAttachmentsForCreate } from '../convert_attachments_for_create'\nimport { generatePlaceholderUlid } from '../generate_placeholder_ulid'\nimport { updateOrCreateRecordInPagesData } from './page_mutations'\n\nexport function optimisticallyCreateMessage({\n conversationId,\n text,\n attachments,\n currentPerson,\n message,\n replyRootId,\n}: {\n conversationId: number\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n currentPerson: CurrentPersonResource\n message?: MessageResource\n replyRootId?: string | null\n}) {\n const id = message?.id || generateTempMessageId()\n\n // Convert attachments to denormalized format for optimistic UI\n const decoratedAttachments: DenormalizedAttachmentResource[] = convertAttachmentsForCreate(\n attachments || []\n )\n\n // Create an optimistic message\n const optimisticMessage: MessageResource = {\n ...message,\n type: 'Message',\n messageType: 'user',\n id,\n text,\n html: '', // Will be filled by server\n createdAt: new Date().toISOString(),\n deletedAt: null,\n textEditedAt: null,\n mine: true,\n attachments: decoratedAttachments,\n attachmentsForCreate: attachments || [],\n author: currentPerson,\n reactionCounts: [],\n renderAuthor: false,\n renderTime: true,\n myLatestInConversation: true,\n lastInGroup: true,\n pending: true,\n replyCount: 0,\n replyRootId: replyRootId || null,\n }\n\n // Add the optimistic message to the cache\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: optimisticMessage as MessageResource,\n })\n )\n\n return optimisticMessage\n}\n\nconst generateTempMessageId = () => {\n // Put it 5 seconds in the future to account for server lag of previously created messages\n // that are still pending. This gets overwritten by the server anyway.\n return `${generatePlaceholderUlid({ offsetMs: 5000 })}-temp`\n}\n"],"mappings":"AACA,SAASA,eAAe,QAAQ,6BAA6B;AAI7D,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,2BAA2B,QAAQ,mCAAmC;AAC/E,SAASC,uBAAuB,QAAQ,8BAA8B;AACtE,SAASC,+BAA+B,QAAQ,kBAAkB;AAElE,OAAO,SAASC,2BAA2BA,CAAC;EAC1CC,cAAc;EACdC,IAAI;EACJC,WAAW;EACXC,aAAa;EACbC,OAAO;EACPC;AAQF,CAAC,EAAE;EACD,MAAMC,EAAE,GAAGF,OAAO,EAAEE,EAAE,IAAIC,qBAAqB,CAAC,CAAC;;EAEjD;EACA,MAAMC,oBAAsD,GAAGZ,2BAA2B,CACxFM,WAAW,IAAI,EACjB,CAAC;;EAED;EACA,MAAMO,iBAAkC,GAAG;IACzC,GAAGL,OAAO;IACVM,IAAI,EAAE,SAAS;IACfC,WAAW,EAAE,MAAM;IACnBL,EAAE;IACFL,IAAI;IACJW,IAAI,EAAE,EAAE;IAAE;IACVC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;IACnCC,SAAS,EAAE,IAAI;IACfC,YAAY,EAAE,IAAI;IAClBC,IAAI,EAAE,IAAI;IACVhB,WAAW,EAAEM,oBAAoB;IACjCW,oBAAoB,EAAEjB,WAAW,IAAI,EAAE;IACvCkB,MAAM,EAAEjB,aAAa;IACrBkB,cAAc,EAAE,EAAE;IAClBC,YAAY,EAAE,KAAK;IACnBC,UAAU,EAAE,IAAI;IAChBC,sBAAsB,EAAE,IAAI;IAC5BC,WAAW,EAAE,IAAI;IACjBC,OAAO,EAAE,IAAI;IACbC,UAAU,EAAE,CAAC;IACbtB,WAAW,EAAEA,WAAW,IAAI;EAC9B,CAAC;;EAED;;EAEA,MAAMuB,QAAQ,GAAGjC,mBAAmB,CAAC;IACnCkC,eAAe,EAAE7B,cAAc;IAC/B8B,aAAa,EAAEzB;EACjB,CAAC,CAAC;EAEFX,eAAe,CAACqC,YAAY,CAAYH,QAAQ,EAAEI,IAAI,IACpDlC,+BAA+B,CAAC;IAC9BkC,IAAI;IACJC,MAAM,EAAExB;EACV,CAAC,CACH,CAAC;EAED,OAAOA,iBAAiB;AAC1B;AAEA,MAAMF,qBAAqB,GAAGA,CAAA,KAAM;EAClC;EACA;EACA,OAAO,GAAGV,uBAAuB,CAAC;IAAEqC,QAAQ,EAAE;EAAK,CAAC,CAAC,OAAO;AAC9D,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"optimistically_create_message.js","names":["chatQueryClient","getMessagesQueryKey","convertAttachmentsForCreate","generatePlaceholderUlid","updateOrCreateRecordInPagesData","optimisticallyCreateMessage","conversationId","text","attachments","currentPerson","message","replyRootId","idempotentKey","id","generateTempMessageId","decoratedAttachments","optimisticMessage","type","messageType","html","createdAt","Date","toISOString","deletedAt","textEditedAt","mine","attachmentsForCreate","author","reactionCounts","renderAuthor","renderTime","myLatestInConversation","lastInGroup","pending","replyCount","queryKey","conversation_id","reply_root_id","setQueryData","data","record","offsetMs"],"sources":["../../../src/utils/cache/optimistically_create_message.ts"],"sourcesContent":["import { InfiniteData } from '@tanstack/react-query'\nimport { chatQueryClient } from '../../contexts/api_provider'\nimport { ApiCollection, CurrentPersonResource, MessageResource } from '../../types'\nimport { DenormalizedAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport { DenormalizedAttachmentResourceForCreate } from '../../types/resources/denormalized_attachment_resource_for_create'\nimport { getMessagesQueryKey } from '../../utils/request/get_messages'\nimport { convertAttachmentsForCreate } from '../convert_attachments_for_create'\nimport { generatePlaceholderUlid } from '../generate_placeholder_ulid'\nimport { updateOrCreateRecordInPagesData } from './page_mutations'\n\nexport function optimisticallyCreateMessage({\n conversationId,\n text,\n attachments,\n currentPerson,\n message,\n replyRootId,\n idempotentKey,\n}: {\n conversationId: number\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n currentPerson: CurrentPersonResource\n message?: MessageResource\n replyRootId?: string | null\n idempotentKey?: string\n}) {\n const id = message?.id || generateTempMessageId()\n\n // Convert attachments to denormalized format for optimistic UI\n const decoratedAttachments: DenormalizedAttachmentResource[] = convertAttachmentsForCreate(\n attachments || []\n )\n\n // Create an optimistic message\n const optimisticMessage: MessageResource = {\n ...message,\n type: 'Message',\n messageType: 'user',\n id,\n text,\n html: '', // Will be filled by server\n createdAt: new Date().toISOString(),\n deletedAt: null,\n textEditedAt: null,\n mine: true,\n attachments: decoratedAttachments,\n attachmentsForCreate: attachments || [],\n author: currentPerson,\n reactionCounts: [],\n renderAuthor: false,\n renderTime: true,\n myLatestInConversation: true,\n lastInGroup: true,\n pending: true,\n replyCount: 0,\n replyRootId: replyRootId || null,\n idempotentKey,\n }\n\n // Add the optimistic message to the cache\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: optimisticMessage as MessageResource,\n })\n )\n\n return optimisticMessage\n}\n\nconst generateTempMessageId = () => {\n // Put it 5 seconds in the future to account for server lag of previously created messages\n // that are still pending. This gets overwritten by the server anyway.\n return `${generatePlaceholderUlid({ offsetMs: 5000 })}-temp`\n}\n"],"mappings":"AACA,SAASA,eAAe,QAAQ,6BAA6B;AAI7D,SAASC,mBAAmB,QAAQ,kCAAkC;AACtE,SAASC,2BAA2B,QAAQ,mCAAmC;AAC/E,SAASC,uBAAuB,QAAQ,8BAA8B;AACtE,SAASC,+BAA+B,QAAQ,kBAAkB;AAElE,OAAO,SAASC,2BAA2BA,CAAC;EAC1CC,cAAc;EACdC,IAAI;EACJC,WAAW;EACXC,aAAa;EACbC,OAAO;EACPC,WAAW;EACXC;AASF,CAAC,EAAE;EACD,MAAMC,EAAE,GAAGH,OAAO,EAAEG,EAAE,IAAIC,qBAAqB,CAAC,CAAC;;EAEjD;EACA,MAAMC,oBAAsD,GAAGb,2BAA2B,CACxFM,WAAW,IAAI,EACjB,CAAC;;EAED;EACA,MAAMQ,iBAAkC,GAAG;IACzC,GAAGN,OAAO;IACVO,IAAI,EAAE,SAAS;IACfC,WAAW,EAAE,MAAM;IACnBL,EAAE;IACFN,IAAI;IACJY,IAAI,EAAE,EAAE;IAAE;IACVC,SAAS,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;IACnCC,SAAS,EAAE,IAAI;IACfC,YAAY,EAAE,IAAI;IAClBC,IAAI,EAAE,IAAI;IACVjB,WAAW,EAAEO,oBAAoB;IACjCW,oBAAoB,EAAElB,WAAW,IAAI,EAAE;IACvCmB,MAAM,EAAElB,aAAa;IACrBmB,cAAc,EAAE,EAAE;IAClBC,YAAY,EAAE,KAAK;IACnBC,UAAU,EAAE,IAAI;IAChBC,sBAAsB,EAAE,IAAI;IAC5BC,WAAW,EAAE,IAAI;IACjBC,OAAO,EAAE,IAAI;IACbC,UAAU,EAAE,CAAC;IACbvB,WAAW,EAAEA,WAAW,IAAI,IAAI;IAChCC;EACF,CAAC;;EAED;;EAEA,MAAMuB,QAAQ,GAAGlC,mBAAmB,CAAC;IACnCmC,eAAe,EAAE9B,cAAc;IAC/B+B,aAAa,EAAE1B;EACjB,CAAC,CAAC;EAEFX,eAAe,CAACsC,YAAY,CAAYH,QAAQ,EAAEI,IAAI,IACpDnC,+BAA+B,CAAC;IAC9BmC,IAAI;IACJC,MAAM,EAAExB;EACV,CAAC,CACH,CAAC;EAED,OAAOA,iBAAiB;AAC1B;AAEA,MAAMF,qBAAqB,GAAGA,CAAA,KAAM;EAClC;EACA;EACA,OAAO,GAAGX,uBAAuB,CAAC;IAAEsC,QAAQ,EAAE;EAAK,CAAC,CAAC,OAAO;AAC9D,CAAC","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"transform_response.d.ts","sourceRoot":"","sources":["../../../src/utils/client/transform_response.ts"],"names":[],"mappings":"AAiGA,QAAA,MAAM,iBAAiB,yBAAyD,CAAA;AAEhF,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"transform_response.d.ts","sourceRoot":"","sources":["../../../src/utils/client/transform_response.ts"],"names":[],"mappings":"AAmGA,QAAA,MAAM,iBAAiB,yBAAyD,CAAA;AAEhF,eAAe,iBAAiB,CAAA"}
@@ -36,21 +36,25 @@ const transformRelationships = relationships => {
36
36
  }
37
37
  }, {});
38
38
  };
39
- const addIncludedRecords = (relationships, included, seen, parent) => {
39
+ const addIncludedRecords = (record, included, seen, parent) => {
40
+ const {
41
+ relationships
42
+ } = record;
40
43
  return Object.keys(relationships || {}).reduce((acc, key) => {
41
44
  const relationship = relationships[key];
42
45
  if (_.isArray(relationship.data)) {
43
46
  const records = _(relationship.data).map(elem => _.find(included, elem)).compact() // account for orphans
44
47
  .value();
45
- return _.set(acc, _.pluralize(key), _.map(records, record => transformRecord(record, included, seen)));
48
+ return _.set(acc, _.pluralize(key), _.map(records, related => transformRecord(related, included, seen)));
46
49
  } else {
47
50
  const [id, type] = _.at(relationship, ['data.id', 'data.type']);
48
51
  if (id && type) {
49
- const record = _.find(included, {
52
+ const isSelfReference = id === record.id && type === record.type;
53
+ const related = isSelfReference ? undefined : _.find(included, {
50
54
  id,
51
55
  type
52
56
  });
53
- return _.set(acc, key, record ? transformRecord(record, included, seen) : null);
57
+ return _.set(acc, key, related ? transformRecord(related, included, seen) : null);
54
58
  } else {
55
59
  return acc;
56
60
  }
@@ -77,7 +81,7 @@ const transformRecord = (record, included, seen) => {
77
81
  ..._.mapKeys(attributes, (v, k) => k === 'length' ? `${type.charAt(0).toLowerCase()}${type.slice(1)}Length` : k, {})
78
82
  };
79
83
  seen.set(record, transformed);
80
- return addIncludedRecords(relationships, included, seen, transformed);
84
+ return addIncludedRecords(record, included, seen, transformed);
81
85
  }
82
86
  };
83
87
  const defaultTransformResponse = response => {