@cossistant/react 0.0.3 → 0.0.5

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 (320) hide show
  1. package/README.md +74 -0
  2. package/_virtual/rolldown_runtime.js +19 -0
  3. package/conversation.d.ts +26 -3
  4. package/conversation.d.ts.map +1 -1
  5. package/hooks/index.d.ts +5 -3
  6. package/hooks/index.js +7 -5
  7. package/hooks/private/store/use-conversations-store.d.ts +8 -0
  8. package/hooks/private/store/use-conversations-store.d.ts.map +1 -1
  9. package/hooks/private/store/use-conversations-store.js +8 -0
  10. package/hooks/private/store/use-conversations-store.js.map +1 -1
  11. package/hooks/private/store/use-store-selector.d.ts +4 -0
  12. package/hooks/private/store/use-store-selector.d.ts.map +1 -1
  13. package/hooks/private/store/use-store-selector.js +5 -2
  14. package/hooks/private/store/use-store-selector.js.map +1 -1
  15. package/hooks/private/store/use-website-store.d.ts +4 -0
  16. package/hooks/private/store/use-website-store.d.ts.map +1 -1
  17. package/hooks/private/store/use-website-store.js +6 -3
  18. package/hooks/private/store/use-website-store.js.map +1 -1
  19. package/hooks/private/typing.d.ts +35 -0
  20. package/hooks/private/typing.d.ts.map +1 -0
  21. package/hooks/private/typing.js +49 -0
  22. package/hooks/private/typing.js.map +1 -0
  23. package/hooks/private/use-client-query.d.ts +5 -0
  24. package/hooks/private/use-client-query.d.ts.map +1 -1
  25. package/hooks/private/use-client-query.js +5 -0
  26. package/hooks/private/use-client-query.js.map +1 -1
  27. package/hooks/private/use-grouped-messages.d.ts +10 -4
  28. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  29. package/hooks/private/use-grouped-messages.js +24 -4
  30. package/hooks/private/use-grouped-messages.js.map +1 -1
  31. package/hooks/private/use-multimodal-input.d.ts.map +1 -1
  32. package/hooks/private/use-rest-client.d.ts.map +1 -1
  33. package/hooks/private/use-visitor-typing-reporter.d.ts +6 -0
  34. package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
  35. package/hooks/private/use-visitor-typing-reporter.js +6 -0
  36. package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
  37. package/hooks/use-composer-refocus.d.ts.map +1 -1
  38. package/hooks/use-conversation-auto-seen.d.ts +9 -0
  39. package/hooks/use-conversation-auto-seen.d.ts.map +1 -1
  40. package/hooks/use-conversation-auto-seen.js +44 -3
  41. package/hooks/use-conversation-auto-seen.js.map +1 -1
  42. package/hooks/use-conversation-history-page.d.ts.map +1 -1
  43. package/hooks/use-conversation-history-page.js +16 -18
  44. package/hooks/use-conversation-history-page.js.map +1 -1
  45. package/hooks/use-conversation-lifecycle.d.ts.map +1 -1
  46. package/hooks/use-conversation-lifecycle.js +2 -4
  47. package/hooks/use-conversation-lifecycle.js.map +1 -1
  48. package/hooks/use-conversation-page.d.ts +6 -0
  49. package/hooks/use-conversation-page.d.ts.map +1 -1
  50. package/hooks/use-conversation-page.js +41 -3
  51. package/hooks/use-conversation-page.js.map +1 -1
  52. package/hooks/use-conversation-preview.d.ts +61 -0
  53. package/hooks/use-conversation-preview.d.ts.map +1 -0
  54. package/hooks/use-conversation-preview.js +173 -0
  55. package/hooks/use-conversation-preview.js.map +1 -0
  56. package/hooks/use-conversation-seen.d.ts +4 -0
  57. package/hooks/use-conversation-seen.d.ts.map +1 -1
  58. package/hooks/use-conversation-seen.js +4 -0
  59. package/hooks/use-conversation-seen.js.map +1 -1
  60. package/hooks/use-conversation-timeline-items.d.ts +4 -0
  61. package/hooks/use-conversation-timeline-items.d.ts.map +1 -1
  62. package/hooks/use-conversation-timeline-items.js +4 -0
  63. package/hooks/use-conversation-timeline-items.js.map +1 -1
  64. package/hooks/use-conversation-timeline.d.ts +32 -0
  65. package/hooks/use-conversation-timeline.d.ts.map +1 -0
  66. package/hooks/use-conversation-timeline.js +41 -0
  67. package/hooks/use-conversation-timeline.js.map +1 -0
  68. package/hooks/use-conversation-typing.d.ts +4 -0
  69. package/hooks/use-conversation-typing.d.ts.map +1 -1
  70. package/hooks/use-conversation-typing.js +4 -0
  71. package/hooks/use-conversation-typing.js.map +1 -1
  72. package/hooks/use-conversation.d.ts +11 -0
  73. package/hooks/use-conversation.d.ts.map +1 -1
  74. package/hooks/use-conversation.js +11 -0
  75. package/hooks/use-conversation.js.map +1 -1
  76. package/hooks/use-conversations.d.ts +12 -0
  77. package/hooks/use-conversations.d.ts.map +1 -1
  78. package/hooks/use-conversations.js +12 -0
  79. package/hooks/use-conversations.js.map +1 -1
  80. package/hooks/use-create-conversation.d.ts +5 -0
  81. package/hooks/use-create-conversation.d.ts.map +1 -1
  82. package/hooks/use-create-conversation.js +12 -9
  83. package/hooks/use-create-conversation.js.map +1 -1
  84. package/hooks/use-home-page.d.ts.map +1 -1
  85. package/hooks/use-home-page.js +6 -4
  86. package/hooks/use-home-page.js.map +1 -1
  87. package/hooks/use-message-composer.d.ts.map +1 -1
  88. package/hooks/use-realtime-support.d.ts.map +1 -1
  89. package/hooks/use-send-message.d.ts +9 -0
  90. package/hooks/use-send-message.d.ts.map +1 -1
  91. package/hooks/use-send-message.js +15 -13
  92. package/hooks/use-send-message.js.map +1 -1
  93. package/hooks/use-visitor.d.ts.map +1 -1
  94. package/hooks/use-visitor.js +28 -30
  95. package/hooks/use-visitor.js.map +1 -1
  96. package/hooks/use-window-visibility-focus.d.ts +4 -0
  97. package/hooks/use-window-visibility-focus.d.ts.map +1 -1
  98. package/hooks/use-window-visibility-focus.js +5 -2
  99. package/hooks/use-window-visibility-focus.js.map +1 -1
  100. package/identify-visitor.d.ts +12 -3
  101. package/identify-visitor.d.ts.map +1 -1
  102. package/identify-visitor.js +58 -9
  103. package/identify-visitor.js.map +1 -1
  104. package/index.d.ts +10 -7
  105. package/index.js +10 -9
  106. package/package.json +14 -17
  107. package/primitives/avatar/avatar.d.ts.map +1 -1
  108. package/primitives/avatar/fallback.d.ts.map +1 -1
  109. package/primitives/avatar/fallback.js +1 -3
  110. package/primitives/avatar/fallback.js.map +1 -1
  111. package/primitives/avatar/image.d.ts.map +1 -1
  112. package/primitives/avatar/index.d.ts +1 -0
  113. package/primitives/bubble.d.ts +2 -0
  114. package/primitives/bubble.d.ts.map +1 -1
  115. package/primitives/bubble.js +8 -2
  116. package/primitives/bubble.js.map +1 -1
  117. package/primitives/button.d.ts.map +1 -1
  118. package/primitives/conversation-timeline.d.ts.map +1 -1
  119. package/primitives/conversation-timeline.js +58 -5
  120. package/primitives/conversation-timeline.js.map +1 -1
  121. package/primitives/index.d.ts +1 -0
  122. package/primitives/index.parts.d.ts +1 -0
  123. package/primitives/multimodal-input.d.ts.map +1 -1
  124. package/primitives/timeline-item-group.d.ts +7 -7
  125. package/primitives/timeline-item-group.d.ts.map +1 -1
  126. package/primitives/timeline-item-group.js.map +1 -1
  127. package/primitives/timeline-item.d.ts +1 -1
  128. package/primitives/timeline-item.d.ts.map +1 -1
  129. package/primitives/timeline-item.js +7 -1
  130. package/primitives/timeline-item.js.map +1 -1
  131. package/primitives/window.d.ts +1 -1
  132. package/primitives/window.d.ts.map +1 -1
  133. package/primitives/window.js +4 -4
  134. package/primitives/window.js.map +1 -1
  135. package/provider.d.ts +23 -43
  136. package/provider.d.ts.map +1 -1
  137. package/provider.js +152 -49
  138. package/provider.js.map +1 -1
  139. package/realtime/event-filter.d.ts +4 -0
  140. package/realtime/event-filter.d.ts.map +1 -1
  141. package/realtime/event-filter.js +4 -0
  142. package/realtime/event-filter.js.map +1 -1
  143. package/realtime/index.js +1 -1
  144. package/realtime/provider.d.ts +7 -2
  145. package/realtime/provider.d.ts.map +1 -1
  146. package/realtime/provider.js +23 -1
  147. package/realtime/provider.js.map +1 -1
  148. package/realtime/seen-store.d.ts +13 -0
  149. package/realtime/seen-store.d.ts.map +1 -1
  150. package/realtime/seen-store.js +14 -2
  151. package/realtime/seen-store.js.map +1 -1
  152. package/realtime/support-provider.d.ts +1 -2
  153. package/realtime/support-provider.d.ts.map +1 -1
  154. package/realtime/support-provider.js +19 -20
  155. package/realtime/support-provider.js.map +1 -1
  156. package/realtime/typing-store.d.ts +18 -0
  157. package/realtime/typing-store.d.ts.map +1 -1
  158. package/realtime/typing-store.js +19 -2
  159. package/realtime/typing-store.js.map +1 -1
  160. package/realtime/use-realtime.d.ts +8 -4
  161. package/realtime/use-realtime.d.ts.map +1 -1
  162. package/realtime/use-realtime.js +4 -0
  163. package/realtime/use-realtime.js.map +1 -1
  164. package/realtime-events.d.ts +17 -3
  165. package/realtime-events.d.ts.map +1 -1
  166. package/schemas.d.ts +7 -1
  167. package/schemas.d.ts.map +1 -1
  168. package/support/components/avatar-stack.d.ts +8 -4
  169. package/support/components/avatar-stack.d.ts.map +1 -1
  170. package/support/components/avatar-stack.js +4 -0
  171. package/support/components/avatar-stack.js.map +1 -1
  172. package/support/components/avatar.d.ts +11 -6
  173. package/support/components/avatar.d.ts.map +1 -1
  174. package/support/components/avatar.js +4 -0
  175. package/support/components/avatar.js.map +1 -1
  176. package/support/components/bubble.d.ts.map +1 -1
  177. package/support/components/bubble.js +29 -6
  178. package/support/components/bubble.js.map +1 -1
  179. package/support/components/button.d.ts +8 -5
  180. package/support/components/button.d.ts.map +1 -1
  181. package/support/components/button.js +5 -1
  182. package/support/components/button.js.map +1 -1
  183. package/support/components/container.d.ts +0 -1
  184. package/support/components/container.d.ts.map +1 -1
  185. package/support/components/container.js +2 -8
  186. package/support/components/container.js.map +1 -1
  187. package/support/components/conversation-button-link.d.ts +8 -21
  188. package/support/components/conversation-button-link.d.ts.map +1 -1
  189. package/support/components/conversation-button-link.js +62 -178
  190. package/support/components/conversation-button-link.js.map +1 -1
  191. package/support/components/conversation-event.d.ts.map +1 -1
  192. package/support/components/conversation-event.js +4 -0
  193. package/support/components/conversation-event.js.map +1 -1
  194. package/support/components/conversation-timeline.d.ts +10 -1
  195. package/support/components/conversation-timeline.d.ts.map +1 -1
  196. package/support/components/conversation-timeline.js +63 -57
  197. package/support/components/conversation-timeline.js.map +1 -1
  198. package/support/components/cossistant-branding.d.ts +5 -2
  199. package/support/components/cossistant-branding.d.ts.map +1 -1
  200. package/support/components/cossistant-branding.js +3 -0
  201. package/support/components/cossistant-branding.js.map +1 -1
  202. package/support/components/header.d.ts.map +1 -1
  203. package/support/components/header.js +2 -2
  204. package/support/components/header.js.map +1 -1
  205. package/support/components/icons.d.ts.map +1 -1
  206. package/support/components/multimodal-input.d.ts.map +1 -1
  207. package/support/components/multimodal-input.js +5 -24
  208. package/support/components/multimodal-input.js.map +1 -1
  209. package/support/components/navigation-tab.d.ts +7 -2
  210. package/support/components/navigation-tab.d.ts.map +1 -1
  211. package/support/components/navigation-tab.js +4 -0
  212. package/support/components/navigation-tab.js.map +1 -1
  213. package/support/components/support-content.d.ts +1 -1
  214. package/support/components/support-content.d.ts.map +1 -1
  215. package/support/components/support-content.js +7 -10
  216. package/support/components/support-content.js.map +1 -1
  217. package/support/components/text-effect.d.ts +5 -2
  218. package/support/components/text-effect.d.ts.map +1 -1
  219. package/support/components/text-effect.js +4 -0
  220. package/support/components/text-effect.js.map +1 -1
  221. package/support/components/timeline-identification-tool.d.ts +7 -0
  222. package/support/components/timeline-identification-tool.d.ts.map +1 -0
  223. package/support/components/timeline-identification-tool.js +139 -0
  224. package/support/components/timeline-identification-tool.js.map +1 -0
  225. package/support/components/timeline-message-group.d.ts +2 -1
  226. package/support/components/timeline-message-group.d.ts.map +1 -1
  227. package/support/components/timeline-message-group.js +4 -19
  228. package/support/components/timeline-message-group.js.map +1 -1
  229. package/support/components/timeline-message-item.d.ts +6 -2
  230. package/support/components/timeline-message-item.d.ts.map +1 -1
  231. package/support/components/timeline-message-item.js +8 -4
  232. package/support/components/timeline-message-item.js.map +1 -1
  233. package/support/components/typing-indicator.d.ts +5 -2
  234. package/support/components/typing-indicator.d.ts.map +1 -1
  235. package/support/components/typing-indicator.js +4 -4
  236. package/support/components/typing-indicator.js.map +1 -1
  237. package/support/components/watermark.d.ts.map +1 -1
  238. package/support/context/websocket.d.ts +8 -0
  239. package/support/context/websocket.d.ts.map +1 -1
  240. package/support/context/websocket.js +12 -6
  241. package/support/context/websocket.js.map +1 -1
  242. package/support/index.d.ts +8 -8
  243. package/support/index.d.ts.map +1 -1
  244. package/support/index.js +18 -18
  245. package/support/index.js.map +1 -1
  246. package/support/pages/conversation-history.js +46 -54
  247. package/support/pages/conversation-history.js.map +1 -1
  248. package/support/pages/conversation.d.ts +3 -6
  249. package/support/pages/conversation.d.ts.map +1 -1
  250. package/support/pages/conversation.js +19 -9
  251. package/support/pages/conversation.js.map +1 -1
  252. package/support/pages/home.d.ts +2 -2
  253. package/support/pages/home.d.ts.map +1 -1
  254. package/support/pages/home.js +64 -77
  255. package/support/pages/home.js.map +1 -1
  256. package/support/store/support-store.d.ts +18 -2
  257. package/support/store/support-store.d.ts.map +1 -1
  258. package/support/store/support-store.js +20 -5
  259. package/support/store/support-store.js.map +1 -1
  260. package/support/{support-CMoDLQoC.css → support-Ck4jy29i.css} +1 -2
  261. package/support/support-Ck4jy29i.css.map +1 -0
  262. package/support/text/index.d.ts +15 -2
  263. package/support/text/index.d.ts.map +1 -1
  264. package/support/text/index.js +15 -2
  265. package/support/text/index.js.map +1 -1
  266. package/support/text/locales/en.js +22 -4
  267. package/support/text/locales/en.js.map +1 -1
  268. package/support/text/locales/es.js +18 -0
  269. package/support/text/locales/es.js.map +1 -1
  270. package/support/text/locales/fr.js +18 -0
  271. package/support/text/locales/fr.js.map +1 -1
  272. package/support/text/locales/keys.d.ts +69 -9
  273. package/support/text/locales/keys.d.ts.map +1 -1
  274. package/support/text/locales/keys.js +18 -0
  275. package/support/text/locales/keys.js.map +1 -1
  276. package/support/text/runtime.d.ts +21 -0
  277. package/support/text/runtime.d.ts.map +1 -1
  278. package/support/text/runtime.js +21 -0
  279. package/support/text/runtime.js.map +1 -1
  280. package/support/utils/index.d.ts +4 -0
  281. package/support/utils/index.d.ts.map +1 -1
  282. package/support/utils/index.js +4 -1
  283. package/support/utils/index.js.map +1 -1
  284. package/support/utils/time.d.ts +3 -0
  285. package/support/utils/time.d.ts.map +1 -1
  286. package/support/utils/time.js +3 -0
  287. package/support/utils/time.js.map +1 -1
  288. package/support-config.d.ts +2 -1
  289. package/support-config.d.ts.map +1 -1
  290. package/support-config.js.map +1 -1
  291. package/support.css +2 -2
  292. package/timeline-item.d.ts +10 -0
  293. package/timeline-item.d.ts.map +1 -1
  294. package/utils/conversation.d.ts +7 -0
  295. package/utils/conversation.d.ts.map +1 -0
  296. package/utils/conversation.js +18 -0
  297. package/utils/conversation.js.map +1 -0
  298. package/utils/id.d.ts +3 -0
  299. package/utils/id.d.ts.map +1 -1
  300. package/utils/id.js +3 -0
  301. package/utils/id.js.map +1 -1
  302. package/utils/index.d.ts +2 -1
  303. package/utils/index.js +2 -1
  304. package/utils/metadata-hash.d.ts +12 -0
  305. package/utils/metadata-hash.d.ts.map +1 -0
  306. package/utils/metadata-hash.js +26 -0
  307. package/utils/metadata-hash.js.map +1 -0
  308. package/utils/text.d.ts +3 -0
  309. package/utils/text.d.ts.map +1 -1
  310. package/utils/text.js +3 -0
  311. package/utils/text.js.map +1 -1
  312. package/utils/use-render-element.d.ts +3 -0
  313. package/utils/use-render-element.d.ts.map +1 -1
  314. package/utils/use-render-element.js +3 -0
  315. package/utils/use-render-element.js.map +1 -1
  316. package/support/context/config.d.ts +0 -32
  317. package/support/context/config.d.ts.map +0 -1
  318. package/support/context/config.js +0 -27
  319. package/support/context/config.js.map +0 -1
  320. package/support/support-CMoDLQoC.css.map +0 -1
package/provider.d.ts CHANGED
@@ -1,12 +1,10 @@
1
- import * as React$1 from "react";
1
+ import React from "react";
2
2
  import { CossistantClient } from "@cossistant/core";
3
3
  import { DefaultMessage, PublicWebsiteResponse } from "@cossistant/types";
4
- import * as react_jsx_runtime0 from "react/jsx-runtime";
5
- import { QueryClient } from "@tanstack/react-query";
6
4
 
7
5
  //#region src/provider.d.ts
8
6
  type SupportProviderProps = {
9
- children: React$1.ReactNode;
7
+ children: React.ReactNode;
10
8
  defaultOpen?: boolean;
11
9
  apiUrl?: string;
12
10
  wsUrl?: string;
@@ -17,7 +15,7 @@ type SupportProviderProps = {
17
15
  onWsConnect?: () => void;
18
16
  onWsDisconnect?: () => void;
19
17
  onWsError?: (error: Error) => void;
20
- queryClient?: QueryClient;
18
+ size?: "normal" | "larger";
21
19
  };
22
20
  type CossistantProviderProps = SupportProviderProps;
23
21
  type CossistantContextValue = {
@@ -31,7 +29,22 @@ type CossistantContextValue = {
31
29
  isLoading: boolean;
32
30
  error: Error | null;
33
31
  client: CossistantClient;
32
+ isOpen: boolean;
33
+ open: () => void;
34
+ close: () => void;
35
+ toggle: () => void;
34
36
  };
37
+ type WebsiteData = NonNullable<CossistantContextValue["website"]>;
38
+ type VisitorWithLocale = WebsiteData["visitor"] extends null | undefined ? undefined : NonNullable<WebsiteData["visitor"]> & {
39
+ locale: string | null;
40
+ };
41
+ type UseSupportValue = CossistantContextValue & {
42
+ availableHumanAgents: NonNullable<WebsiteData["availableHumanAgents"]> | [];
43
+ availableAIAgents: NonNullable<WebsiteData["availableAIAgents"]> | [];
44
+ visitor?: VisitorWithLocale;
45
+ size: "normal" | "larger";
46
+ };
47
+ declare const SupportContext: React.Context<CossistantContextValue | undefined>;
35
48
  /**
36
49
  * Hosts the entire customer support widget ecosystem by handing out context
37
50
  * about the current website, visitor, unread counts, realtime subscriptions
@@ -49,47 +62,14 @@ declare function SupportProvider({
49
62
  onWsConnect,
50
63
  onWsDisconnect,
51
64
  onWsError,
52
- queryClient
53
- }: SupportProviderProps): react_jsx_runtime0.JSX.Element;
65
+ size,
66
+ defaultOpen
67
+ }: SupportProviderProps): React.ReactElement;
54
68
  /**
55
69
  * Convenience hook that exposes the aggregated support context. Throws when it
56
70
  * is consumed outside of `SupportProvider` to catch integration mistakes.
57
71
  */
58
- declare function useSupport(): {
59
- availableHumanAgents: {
60
- id: string;
61
- name: string;
62
- image: string | null;
63
- lastSeenAt: string | null;
64
- }[];
65
- availableAIAgents: {
66
- id: string;
67
- name: string;
68
- image: string | null;
69
- }[];
70
- visitor: {
71
- locale: string | null;
72
- id: string;
73
- isBlocked: boolean;
74
- language: string | null;
75
- contact: {
76
- id: string;
77
- name: string | null;
78
- email: string | null;
79
- image: string | null;
80
- } | null;
81
- } | undefined;
82
- website: PublicWebsiteResponse | null;
83
- defaultMessages: DefaultMessage[];
84
- quickOptions: string[];
85
- setDefaultMessages: (messages: DefaultMessage[]) => void;
86
- setQuickOptions: (options: string[]) => void;
87
- unreadCount: number;
88
- setUnreadCount: (count: number) => void;
89
- isLoading: boolean;
90
- error: Error | null;
91
- client: CossistantClient;
92
- };
72
+ declare function useSupport(): UseSupportValue;
93
73
  //#endregion
94
- export { CossistantContextValue, CossistantProviderProps, SupportProvider, SupportProviderProps, useSupport };
74
+ export { CossistantContextValue, CossistantProviderProps, SupportContext, SupportProvider, SupportProviderProps, UseSupportValue, useSupport };
95
75
  //# sourceMappingURL=provider.d.ts.map
package/provider.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","names":[],"sources":["../src/provider.tsx"],"sourcesContent":[],"mappings":";;;;;;;KASY,oBAAA;YACD,OAAA,CAAM;;EADL,MAAA,CAAA,EAAA,MAAA;EAAoB,KAAA,CAAA,EAAA,MAAA;WACrB,CAAA,EAAM,MAAA;iBAKE,CAAA,EAAA,cAAA,EAAA;cAKE,CAAA,EAAA,MAAA,EAAA;aACN,CAAA,EAAA,OAAA;EAAW,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAGd,cAAA,CAAA,EAAA,GAAA,GAAA,IAAuB;EAEvB,SAAA,CAAA,EAAA,CAAA,KAAA,EANS,KAMa,EAAA,GAAA,IAAA;EAAA,WAAA,CAAA,EALnB,WAKmB;;AAEhB,KAJN,uBAAA,GAA0B,oBAIpB;AAEc,KAJpB,sBAAA,GAIoB;SAKxB,EARE,qBAQF,GAAA,IAAA;iBACC,EARS,cAQT,EAAA;EAAgB,YAAA,EAAA,MAAA,EAAA;EA+HT,kBAAe,EAAA,CAAA,QAAA,EArIC,cAqID,EAAA,EAAA,GAAA,IAAA;EAAA,eAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,EAAA,GAAA,IAAA;aAC9B,EAAA,MAAA;gBACA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;WACA,EAAA,OAAA;OACA,EApIO,KAoIP,GAAA,IAAA;QACA,EApIQ,gBAoIR;;;;;;;;AAOsB,iBAZP,eAAA,CAYO;EAAA,QAAA;EAAA,MAAA;EAAA,KAAA;EAAA,SAAA;EAAA,eAAA;EAAA,YAAA;EAAA,WAAA;EAAA,WAAA;EAAA,cAAA;EAAA,SAAA;EAAA;AAAA,CAAA,EAApB,oBAAoB,CAAA,EAAA,kBAAA,CAAA,GAAA,CAAA,OAAA;;AAuCvB;;;AA1LkB,iBA0LF,UAAA,CAAA,CA1LE,EAAA;sBAEc,EAAA;IAKxB,EAAA,EAAA,MAAA;IACC,IAAA,EAAA,MAAA;IAAgB,KAAA,EAAA,MAAA,GAAA,IAAA;;;;;;;;;;;;;;;;;;;;WATf;mBACQ;;iCAEc;;;;;SAKxB;UACC"}
1
+ {"version":3,"file":"provider.d.ts","names":[],"sources":["../src/provider.tsx"],"sourcesContent":[],"mappings":";;;;;KAgBY,oBAAA;YACD,KAAA,CAAM;EADL,WAAA,CAAA,EAAA,OAAA;EACD,MAAM,CAAA,EAAA,MAAA;EAKE,KAAA,CAAA,EAAA,MAAA;EAKE,SAAA,CAAA,EAAA,MAAA;EAAK,eAAA,CAAA,EALP,cAKO,EAAA;EAId,YAAA,CAAA,EAAA,MAAA,EAAA;EAEA,WAAA,CAAA,EAAA,OAAA;EACF,WAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EACQ,cAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EAEc,SAAA,CAAA,EAAA,CAAA,KAAA,EAVX,KAUW,EAAA,GAAA,IAAA;EAKxB,IAAA,CAAA,EAAA,QAAA,GAAA,QAAA;CACC;AAAgB,KAZb,uBAAA,GAA0B,oBAYb;AAOpB,KAjBO,sBAAA,GAiBmB;EAE1B,OAAA,EAlBK,qBAkBY,GAAA,IAAA;EAAG,eAAA,EAjBP,cAiBO,EAAA;EAEV,YAAA,EAAA,MAAA,EAAA;EAAZ,kBAAA,EAAA,CAAA,QAAA,EAjB6B,cAiB7B,EAAA,EAAA,GAAA,IAAA;EAAW,eAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,EAAA,GAAA,IAAA;EAwCF,WAAA,EAAA,MAAe;EAAG,cAAA,EAAA,CAAA,KAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EACK,SAAA,EAAA,OAAA;EAAZ,KAAA,EArDf,KAqDe,GAAA,IAAA;EACS,MAAA,EArDvB,gBAqDuB;EAAZ,MAAA,EAAA,OAAA;EACT,IAAA,EAAA,GAAA,GAAA,IAAA;EAAiB,KAAA,EAAA,GAAA,GAAA,IAAA;EAIf,MAAA,EAAA,GAAA,GAAA,IAED;AAiRZ,CAAA;KAtUK,WAAA,GAAc,WAuUlB,CAvU8B,sBAuU9B,CAAA,SAAA,CAAA,CAAA;KArUI,iBAAA,GAAoB,WAsUxB,CAAA,SAAA,CAAA,SAAA,IAAA,GAAA,SAAA,GAAA,SAAA,GApUE,WAoUF,CApUc,WAoUd,CAAA,SAAA,CAAA,CAAA,GAAA;EACA,MAAA,EAAA,MAAA,GAAA,IAAA;CACA;AACA,KA/RW,eAAA,GAAkB,sBA+R7B,GAAA;EACA,oBAAA,EA/RsB,WA+RtB,CA/RkC,WA+RlC,CAAA,sBAAA,CAAA,CAAA,GAAA,EAAA;EACA,iBAAA,EA/RmB,WA+RnB,CA/R+B,WA+R/B,CAAA,mBAAA,CAAA,CAAA,GAAA,EAAA;EACA,OAAA,CAAA,EA/RU,iBA+RV;EACA,IAAA,EAAA,QAAA,GAAA,QAAA;CACA;AACA,cA9RY,cA8RZ,EA9R0B,KAAA,CAAA,OA8R1B,CA9R0B,sBA8R1B,GAAA,SAAA,CAAA;;;;;AA0BD;;iBArCgB,eAAA;;;;;;;;;;;;;GAab,uBAAuB,KAAA,CAAM;;;;;iBAwBhB,UAAA,CAAA,GAAc"}
package/provider.js CHANGED
@@ -1,48 +1,145 @@
1
- import { QueryClient } from "./node_modules/@tanstack/query-core/build/modern/queryClient.js";
2
- import { QueryClientProvider } from "./node_modules/@tanstack/react-query/build/modern/QueryClientProvider.js";
1
+ import { useStoreSelector } from "./hooks/private/store/use-store-selector.js";
3
2
  import { useWebsiteStore } from "./hooks/private/store/use-website-store.js";
4
3
  import { useClient } from "./hooks/private/use-rest-client.js";
4
+ import { useSeenStore } from "./realtime/seen-store.js";
5
+ import { initializeSupportStore, useSupportStore } from "./support/store/support-store.js";
5
6
  import { WebSocketProvider } from "./support/context/websocket.js";
6
- import * as React$1 from "react";
7
+ import React from "react";
7
8
  import { normalizeLocale } from "@cossistant/core";
9
+ import { ConversationTimelineType } from "@cossistant/types/enums";
8
10
  import { jsx } from "react/jsx-runtime";
9
11
 
10
12
  //#region src/provider.tsx
11
- const SupportContext = React$1.createContext(void 0);
13
+ function areConversationSnapshotsEqual(a, b) {
14
+ if (a === b) return true;
15
+ if (a.length !== b.length) return false;
16
+ for (let index = 0; index < a.length; index += 1) {
17
+ const snapshotA = a[index];
18
+ const snapshotB = b[index];
19
+ if (!snapshotA) return false;
20
+ if (!snapshotB) return false;
21
+ const aLastCreatedAt = snapshotA.lastTimelineItem?.createdAt ?? null;
22
+ const bLastCreatedAt = snapshotB.lastTimelineItem?.createdAt ?? null;
23
+ if (snapshotA.id !== snapshotB.id || aLastCreatedAt !== bLastCreatedAt) return false;
24
+ }
25
+ return true;
26
+ }
27
+ const SupportContext = React.createContext(void 0);
12
28
  /**
13
- * Internal implementation that wires the React Query cache, REST client and
14
- * websocket provider together before exposing the combined context.
29
+ * Internal implementation that wires the REST client and websocket provider
30
+ * together before exposing the combined context.
15
31
  */
16
- function SupportProviderInner({ children, apiUrl, wsUrl, publicKey, defaultMessages, quickOptions, autoConnect, onWsConnect, onWsDisconnect, onWsError }) {
17
- const [unreadCount, setUnreadCount] = React$1.useState(0);
18
- const [_defaultMessages, _setDefaultMessages] = React$1.useState(defaultMessages || []);
19
- const [_quickOptions, _setQuickOptions] = React$1.useState(quickOptions || []);
20
- React$1.useEffect(() => {
21
- if (defaultMessages && defaultMessages.length > 0) _setDefaultMessages(defaultMessages);
32
+ function SupportProviderInner({ children, apiUrl, wsUrl, publicKey, defaultMessages, quickOptions, autoConnect, onWsConnect, onWsDisconnect, onWsError, size = "normal", defaultOpen = false }) {
33
+ const [unreadCount, setUnreadCount] = React.useState(0);
34
+ const prefetchedVisitorRef = React.useRef(null);
35
+ const [_defaultMessages, _setDefaultMessages] = React.useState(defaultMessages ?? []);
36
+ const [_quickOptions, _setQuickOptions] = React.useState(quickOptions ?? []);
37
+ React.useEffect(() => {
38
+ initializeSupportStore({
39
+ size,
40
+ defaultOpen
41
+ });
42
+ }, [size, defaultOpen]);
43
+ const { config, open, close, toggle } = useSupportStore();
44
+ React.useEffect(() => {
45
+ if (defaultMessages?.length) _setDefaultMessages(defaultMessages);
22
46
  }, [defaultMessages]);
23
- React$1.useEffect(() => {
24
- if (quickOptions && quickOptions.length > 0) _setQuickOptions(quickOptions);
47
+ React.useEffect(() => {
48
+ if (quickOptions?.length) _setQuickOptions(quickOptions);
25
49
  }, [quickOptions]);
26
50
  const { client } = useClient(publicKey, apiUrl, wsUrl);
27
51
  const { website, isLoading, error: websiteError } = useWebsiteStore(client);
28
- const error = websiteError;
29
- React$1.useEffect(() => {
30
- if (website) client.restClient?.setWebsiteContext?.(website.id, website.visitor?.id);
52
+ const isVisitorBlocked = website?.visitor?.isBlocked ?? false;
53
+ const visitorId = website?.visitor?.id ?? null;
54
+ const seenEntriesByConversation = useSeenStore(React.useCallback((state) => state.conversations, []));
55
+ const conversationSnapshots = useStoreSelector(client.conversationsStore, React.useCallback((state) => state.ids.map((id) => {
56
+ const conversation = state.byId[id];
57
+ if (!conversation) return null;
58
+ return {
59
+ id: conversation.id,
60
+ lastTimelineItem: conversation.lastTimelineItem ?? null
61
+ };
62
+ }).filter((snapshot) => snapshot !== null), []), areConversationSnapshotsEqual);
63
+ const derivedUnreadCount = React.useMemo(() => {
64
+ if (!visitorId) return 0;
65
+ let count = 0;
66
+ for (const { id: conversationId, lastTimelineItem } of conversationSnapshots) {
67
+ if (!lastTimelineItem) continue;
68
+ if (lastTimelineItem.type !== ConversationTimelineType.MESSAGE) continue;
69
+ if (lastTimelineItem.visitorId && lastTimelineItem.visitorId === visitorId) continue;
70
+ const createdAtTime = Date.parse(lastTimelineItem.createdAt);
71
+ if (Number.isNaN(createdAtTime)) continue;
72
+ const seenEntries = seenEntriesByConversation[conversationId];
73
+ if (seenEntries) {
74
+ const visitorSeenEntry = Object.values(seenEntries).find((entry) => entry.actorType === "visitor" && entry.actorId === visitorId);
75
+ if (visitorSeenEntry) {
76
+ const lastSeenTime = Date.parse(visitorSeenEntry.lastSeenAt);
77
+ if (!Number.isNaN(lastSeenTime) && createdAtTime <= lastSeenTime) continue;
78
+ }
79
+ }
80
+ count += 1;
81
+ }
82
+ return count;
83
+ }, [
84
+ conversationSnapshots,
85
+ seenEntriesByConversation,
86
+ visitorId
87
+ ]);
88
+ React.useEffect(() => {
89
+ setUnreadCount(derivedUnreadCount);
90
+ }, [derivedUnreadCount, setUnreadCount]);
91
+ React.useEffect(() => {
92
+ if (!website) return;
93
+ client.setWebsiteContext(website.id, website.visitor?.id ?? void 0);
31
94
  }, [client, website]);
32
- const setDefaultMessages = React$1.useCallback((messages) => _setDefaultMessages(messages), []);
33
- const setQuickOptions = React$1.useCallback((options) => _setQuickOptions(options), []);
34
- const setUnreadCountStable = React$1.useCallback((count) => setUnreadCount(count), []);
35
- const value = React$1.useMemo(() => ({
95
+ React.useEffect(() => {
96
+ if (isVisitorBlocked) {
97
+ prefetchedVisitorRef.current = null;
98
+ return;
99
+ }
100
+ if (!autoConnect) return;
101
+ if (!website) return;
102
+ if (!visitorId) return;
103
+ if (prefetchedVisitorRef.current === visitorId) return;
104
+ const hasExistingConversations = client.conversationsStore.getState().ids.length > 0;
105
+ prefetchedVisitorRef.current = visitorId;
106
+ if (hasExistingConversations) return;
107
+ client.listConversations().catch((err) => {
108
+ console.error("[SupportProvider] Failed to prefetch conversations", err);
109
+ prefetchedVisitorRef.current = null;
110
+ });
111
+ }, [
112
+ autoConnect,
113
+ client,
114
+ isVisitorBlocked,
115
+ visitorId,
116
+ website
117
+ ]);
118
+ const error = websiteError;
119
+ React.useEffect(() => {
120
+ client.setVisitorBlocked(isVisitorBlocked);
121
+ }, [client, isVisitorBlocked]);
122
+ const setDefaultMessages = React.useCallback((messages) => {
123
+ _setDefaultMessages(messages);
124
+ }, []);
125
+ const setQuickOptions = React.useCallback((options) => {
126
+ _setQuickOptions(options);
127
+ }, []);
128
+ const value = React.useMemo(() => ({
36
129
  website,
37
130
  unreadCount,
38
- setUnreadCount: setUnreadCountStable,
131
+ setUnreadCount,
39
132
  isLoading,
40
133
  error,
41
134
  client,
42
135
  defaultMessages: _defaultMessages,
43
136
  setDefaultMessages,
44
137
  quickOptions: _quickOptions,
45
- setQuickOptions
138
+ setQuickOptions,
139
+ isOpen: config.isOpen,
140
+ open,
141
+ close,
142
+ toggle
46
143
  }), [
47
144
  website,
48
145
  unreadCount,
@@ -53,21 +150,30 @@ function SupportProviderInner({ children, apiUrl, wsUrl, publicKey, defaultMessa
53
150
  _quickOptions,
54
151
  setDefaultMessages,
55
152
  setQuickOptions,
56
- setUnreadCountStable
153
+ config.isOpen,
154
+ open,
155
+ close,
156
+ toggle
57
157
  ]);
158
+ const webSocketKey = React.useMemo(() => {
159
+ if (!website) return "no-website";
160
+ const visitorKey = website.visitor?.id ?? "anonymous";
161
+ const blockedState = isVisitorBlocked ? "blocked" : "active";
162
+ return `${website.id}:${visitorKey}:${blockedState}`;
163
+ }, [isVisitorBlocked, website]);
58
164
  return /* @__PURE__ */ jsx(SupportContext.Provider, {
59
165
  value,
60
166
  children: /* @__PURE__ */ jsx(WebSocketProvider, {
61
- autoConnect,
167
+ autoConnect: autoConnect && !isVisitorBlocked,
62
168
  onConnect: onWsConnect,
63
169
  onDisconnect: onWsDisconnect,
64
170
  onError: onWsError,
65
171
  publicKey,
66
- visitorId: website?.visitor?.id,
172
+ visitorId: isVisitorBlocked ? void 0 : website?.visitor?.id,
67
173
  websiteId: website?.id,
68
174
  wsUrl,
69
175
  children
70
- })
176
+ }, webSocketKey)
71
177
  });
72
178
  }
73
179
  /**
@@ -76,25 +182,20 @@ function SupportProviderInner({ children, apiUrl, wsUrl, publicKey, defaultMessa
76
182
  * and the REST client. Provide your Cossistant public key plus optional
77
183
  * defaults to configure the widget behaviour.
78
184
  */
79
- function SupportProvider({ children, apiUrl = "https://api.cossistant.com/v1", wsUrl = "wss://api.cossistant.com/ws", publicKey, defaultMessages, quickOptions, autoConnect = true, onWsConnect, onWsDisconnect, onWsError, queryClient }) {
80
- const [defaultQueryClient] = React$1.useState(() => new QueryClient({ defaultOptions: { queries: {
81
- staleTime: 300 * 1e3,
82
- gcTime: 600 * 1e3
83
- } } }));
84
- return /* @__PURE__ */ jsx(QueryClientProvider, {
85
- client: queryClient || defaultQueryClient,
86
- children: /* @__PURE__ */ jsx(SupportProviderInner, {
87
- apiUrl,
88
- autoConnect,
89
- defaultMessages,
90
- onWsConnect,
91
- onWsDisconnect,
92
- onWsError,
93
- publicKey,
94
- quickOptions,
95
- wsUrl,
96
- children
97
- })
185
+ function SupportProvider({ children, apiUrl = "https://api.cossistant.com/v1", wsUrl = "wss://api.cossistant.com/ws", publicKey, defaultMessages, quickOptions, autoConnect = true, onWsConnect, onWsDisconnect, onWsError, size = "normal", defaultOpen = false }) {
186
+ return /* @__PURE__ */ jsx(SupportProviderInner, {
187
+ apiUrl,
188
+ autoConnect,
189
+ defaultMessages,
190
+ defaultOpen,
191
+ onWsConnect,
192
+ onWsDisconnect,
193
+ onWsError,
194
+ publicKey,
195
+ quickOptions,
196
+ size,
197
+ wsUrl,
198
+ children
98
199
  });
99
200
  }
100
201
  /**
@@ -102,11 +203,12 @@ function SupportProvider({ children, apiUrl = "https://api.cossistant.com/v1", w
102
203
  * is consumed outside of `SupportProvider` to catch integration mistakes.
103
204
  */
104
205
  function useSupport() {
105
- const context = React$1.useContext(SupportContext);
206
+ const context = React.useContext(SupportContext);
106
207
  if (!context) throw new Error("useSupport must be used within a cossistant SupportProvider");
107
208
  const availableHumanAgents = context.website?.availableHumanAgents || [];
108
209
  const availableAIAgents = context.website?.availableAIAgents || [];
109
210
  const visitorLanguage = context.website?.visitor?.language || null;
211
+ const { config } = useSupportStore();
110
212
  const visitor = context.website?.visitor ? {
111
213
  ...context.website.visitor,
112
214
  locale: normalizeLocale(visitorLanguage)
@@ -115,10 +217,11 @@ function useSupport() {
115
217
  ...context,
116
218
  availableHumanAgents,
117
219
  availableAIAgents,
118
- visitor
220
+ visitor,
221
+ size: config.size
119
222
  };
120
223
  }
121
224
 
122
225
  //#endregion
123
- export { SupportProvider, useSupport };
226
+ export { SupportContext, SupportProvider, useSupport };
124
227
  //# sourceMappingURL=provider.js.map
package/provider.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","names":["React"],"sources":["../src/provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { normalizeLocale } from \"@cossistant/core\";\nimport type { DefaultMessage, PublicWebsiteResponse } from \"@cossistant/types\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { useWebsiteStore } from \"./hooks/private/store/use-website-store\";\nimport { useClient } from \"./hooks/private/use-rest-client\";\nimport { WebSocketProvider } from \"./support\";\n\nexport type SupportProviderProps = {\n\tchildren: React.ReactNode;\n\tdefaultOpen?: boolean;\n\tapiUrl?: string;\n\twsUrl?: string;\n\tpublicKey?: string;\n\tdefaultMessages?: DefaultMessage[];\n\tquickOptions?: string[];\n\tautoConnect?: boolean;\n\tonWsConnect?: () => void;\n\tonWsDisconnect?: () => void;\n\tonWsError?: (error: Error) => void;\n\tqueryClient?: QueryClient;\n};\n\nexport type CossistantProviderProps = SupportProviderProps;\n\nexport type CossistantContextValue = {\n\twebsite: PublicWebsiteResponse | null;\n\tdefaultMessages: DefaultMessage[];\n\tquickOptions: string[];\n\tsetDefaultMessages: (messages: DefaultMessage[]) => void;\n\tsetQuickOptions: (options: string[]) => void;\n\tunreadCount: number;\n\tsetUnreadCount: (count: number) => void;\n\tisLoading: boolean;\n\terror: Error | null;\n\tclient: CossistantClient;\n};\n\nconst SupportContext = React.createContext<CossistantContextValue | undefined>(\n\tundefined\n);\n\n/**\n * Internal implementation that wires the React Query cache, REST client and\n * websocket provider together before exposing the combined context.\n */\nfunction SupportProviderInner({\n\tchildren,\n\tapiUrl,\n\twsUrl,\n\tpublicKey,\n\tdefaultMessages,\n\tquickOptions,\n\tautoConnect,\n\tonWsConnect,\n\tonWsDisconnect,\n\tonWsError,\n}: SupportProviderProps) {\n\tconst [unreadCount, setUnreadCount] = React.useState(0);\n\tconst [_defaultMessages, _setDefaultMessages] = React.useState<\n\t\tDefaultMessage[]\n\t>(defaultMessages || []);\n\tconst [_quickOptions, _setQuickOptions] = React.useState<string[]>(\n\t\tquickOptions || []\n\t);\n\t// Update state when props change (for initial values from provider)\n\tReact.useEffect(() => {\n\t\tif (defaultMessages && defaultMessages.length > 0) {\n\t\t\t_setDefaultMessages(defaultMessages);\n\t\t}\n\t}, [defaultMessages]);\n\n\tReact.useEffect(() => {\n\t\tif (quickOptions && quickOptions.length > 0) {\n\t\t\t_setQuickOptions(quickOptions);\n\t\t}\n\t}, [quickOptions]);\n\n\tconst { client } = useClient(publicKey, apiUrl, wsUrl);\n\tconst { website, isLoading, error: websiteError } = useWebsiteStore(client);\n\n\t// Prefetch conversations\n\t// useConversations(client, {\n\t// enabled: !!website && !!website.visitor && isClientPrimed,\n\t// });\n\n\tconst error = websiteError;\n\n\t// Prime REST client with website/visitor context so headers are sent reliably\n\tReact.useEffect(() => {\n\t\tif (website) {\n\t\t\t// @ts-expect-error internal priming: safe in our library context\n\t\t\tclient.restClient?.setWebsiteContext?.(website.id, website.visitor?.id);\n\t\t}\n\t}, [client, website]);\n\n\tconst setDefaultMessages = React.useCallback(\n\t\t(messages: DefaultMessage[]) => _setDefaultMessages(messages),\n\t\t[]\n\t);\n\n\tconst setQuickOptions = React.useCallback(\n\t\t(options: string[]) => _setQuickOptions(options),\n\t\t[]\n\t);\n\n\tconst setUnreadCountStable = React.useCallback(\n\t\t(count: number) => setUnreadCount(count),\n\t\t[]\n\t);\n\n\tconst value = React.useMemo<CossistantContextValue>(\n\t\t() => ({\n\t\t\twebsite,\n\t\t\tunreadCount,\n\t\t\tsetUnreadCount: setUnreadCountStable,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tclient,\n\t\t\tdefaultMessages: _defaultMessages,\n\t\t\tsetDefaultMessages,\n\t\t\tquickOptions: _quickOptions,\n\t\t\tsetQuickOptions,\n\t\t}),\n\t\t[\n\t\t\twebsite,\n\t\t\tunreadCount,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tclient,\n\t\t\t_defaultMessages,\n\t\t\t_quickOptions,\n\t\t\tsetDefaultMessages,\n\t\t\tsetQuickOptions,\n\t\t\tsetUnreadCountStable,\n\t\t]\n\t);\n\n\treturn (\n\t\t<SupportContext.Provider value={value}>\n\t\t\t<WebSocketProvider\n\t\t\t\tautoConnect={autoConnect}\n\t\t\t\tonConnect={onWsConnect}\n\t\t\t\tonDisconnect={onWsDisconnect}\n\t\t\t\tonError={onWsError}\n\t\t\t\tpublicKey={publicKey}\n\t\t\t\tvisitorId={website?.visitor?.id}\n\t\t\t\twebsiteId={website?.id}\n\t\t\t\twsUrl={wsUrl}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</WebSocketProvider>\n\t\t</SupportContext.Provider>\n\t);\n}\n\n/**\n * Hosts the entire customer support widget ecosystem by handing out context\n * about the current website, visitor, unread counts, realtime subscriptions\n * and the REST client. Provide your Cossistant public key plus optional\n * defaults to configure the widget behaviour.\n */\nexport function SupportProvider({\n\tchildren,\n\tapiUrl = \"https://api.cossistant.com/v1\",\n\twsUrl = \"wss://api.cossistant.com/ws\",\n\tpublicKey,\n\tdefaultMessages,\n\tquickOptions,\n\tautoConnect = true,\n\tonWsConnect,\n\tonWsDisconnect,\n\tonWsError,\n\tqueryClient,\n}: SupportProviderProps) {\n\t// Create a default QueryClient if none provided\n\tconst [defaultQueryClient] = React.useState(\n\t\t() =>\n\t\t\tnew QueryClient({\n\t\t\t\tdefaultOptions: {\n\t\t\t\t\tqueries: {\n\t\t\t\t\t\tstaleTime: 5 * 60 * 1000, // 5 minutes\n\t\t\t\t\t\tgcTime: 10 * 60 * 1000, // 10 minutes\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t);\n\n\tconst activeQueryClient = queryClient || defaultQueryClient;\n\n\treturn (\n\t\t<QueryClientProvider client={activeQueryClient}>\n\t\t\t<SupportProviderInner\n\t\t\t\tapiUrl={apiUrl}\n\t\t\t\tautoConnect={autoConnect}\n\t\t\t\tdefaultMessages={defaultMessages}\n\t\t\t\tonWsConnect={onWsConnect}\n\t\t\t\tonWsDisconnect={onWsDisconnect}\n\t\t\t\tonWsError={onWsError}\n\t\t\t\tpublicKey={publicKey}\n\t\t\t\tquickOptions={quickOptions}\n\t\t\t\twsUrl={wsUrl}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</SupportProviderInner>\n\t\t</QueryClientProvider>\n\t);\n}\n\n/**\n * Convenience hook that exposes the aggregated support context. Throws when it\n * is consumed outside of `SupportProvider` to catch integration mistakes.\n */\nexport function useSupport() {\n\tconst context = React.useContext(SupportContext);\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"useSupport must be used within a cossistant SupportProvider\"\n\t\t);\n\t}\n\n\tconst availableHumanAgents = context.website?.availableHumanAgents || [];\n\tconst availableAIAgents = context.website?.availableAIAgents || [];\n\tconst visitorLanguage = context.website?.visitor?.language || null;\n\n\t// Create visitor object with normalized locale\n\tconst visitor = context.website?.visitor\n\t\t? {\n\t\t\t\t...context.website.visitor,\n\t\t\t\tlocale: normalizeLocale(visitorLanguage),\n\t\t\t}\n\t\t: undefined;\n\n\treturn {\n\t\t...context,\n\t\tavailableHumanAgents,\n\t\tavailableAIAgents,\n\t\tvisitor,\n\t};\n}\n"],"mappings":";;;;;;;;;;AAuCA,MAAM,iBAAiBA,QAAM,cAC5B,OACA;;;;;AAMD,SAAS,qBAAqB,EAC7B,UACA,QACA,OACA,WACA,iBACA,cACA,aACA,aACA,gBACA,aACwB;CACxB,MAAM,CAAC,aAAa,kBAAkBA,QAAM,SAAS,EAAE;CACvD,MAAM,CAAC,kBAAkB,uBAAuBA,QAAM,SAEpD,mBAAmB,EAAE,CAAC;CACxB,MAAM,CAAC,eAAe,oBAAoBA,QAAM,SAC/C,gBAAgB,EAAE,CAClB;AAED,SAAM,gBAAgB;AACrB,MAAI,mBAAmB,gBAAgB,SAAS,EAC/C,qBAAoB,gBAAgB;IAEnC,CAAC,gBAAgB,CAAC;AAErB,SAAM,gBAAgB;AACrB,MAAI,gBAAgB,aAAa,SAAS,EACzC,kBAAiB,aAAa;IAE7B,CAAC,aAAa,CAAC;CAElB,MAAM,EAAE,WAAW,UAAU,WAAW,QAAQ,MAAM;CACtD,MAAM,EAAE,SAAS,WAAW,OAAO,iBAAiB,gBAAgB,OAAO;CAO3E,MAAM,QAAQ;AAGd,SAAM,gBAAgB;AACrB,MAAI,QAEH,QAAO,YAAY,oBAAoB,QAAQ,IAAI,QAAQ,SAAS,GAAG;IAEtE,CAAC,QAAQ,QAAQ,CAAC;CAErB,MAAM,qBAAqBA,QAAM,aAC/B,aAA+B,oBAAoB,SAAS,EAC7D,EAAE,CACF;CAED,MAAM,kBAAkBA,QAAM,aAC5B,YAAsB,iBAAiB,QAAQ,EAChD,EAAE,CACF;CAED,MAAM,uBAAuBA,QAAM,aACjC,UAAkB,eAAe,MAAM,EACxC,EAAE,CACF;CAED,MAAM,QAAQA,QAAM,eACZ;EACN;EACA;EACA,gBAAgB;EAChB;EACA;EACA;EACA,iBAAiB;EACjB;EACA,cAAc;EACd;EACA,GACD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,CACD;AAED,QACC,oBAAC,eAAe;EAAgB;YAC/B,oBAAC;GACa;GACb,WAAW;GACX,cAAc;GACd,SAAS;GACE;GACX,WAAW,SAAS,SAAS;GAC7B,WAAW,SAAS;GACb;GAEN;IACkB;GACK;;;;;;;;AAU5B,SAAgB,gBAAgB,EAC/B,UACA,SAAS,iCACT,QAAQ,+BACR,WACA,iBACA,cACA,cAAc,MACd,aACA,gBACA,WACA,eACwB;CAExB,MAAM,CAAC,sBAAsBA,QAAM,eAEjC,IAAI,YAAY,EACf,gBAAgB,EACf,SAAS;EACR,WAAW,MAAS;EACpB,QAAQ,MAAU;EAClB,EACD,EACD,CAAC,CACH;AAID,QACC,oBAAC;EAAoB,QAHI,eAAe;YAIvC,oBAAC;GACQ;GACK;GACI;GACJ;GACG;GACL;GACA;GACG;GACP;GAEN;IACqB;GACF;;;;;;AAQxB,SAAgB,aAAa;CAC5B,MAAM,UAAUA,QAAM,WAAW,eAAe;AAChD,KAAI,CAAC,QACJ,OAAM,IAAI,MACT,8DACA;CAGF,MAAM,uBAAuB,QAAQ,SAAS,wBAAwB,EAAE;CACxE,MAAM,oBAAoB,QAAQ,SAAS,qBAAqB,EAAE;CAClE,MAAM,kBAAkB,QAAQ,SAAS,SAAS,YAAY;CAG9D,MAAM,UAAU,QAAQ,SAAS,UAC9B;EACA,GAAG,QAAQ,QAAQ;EACnB,QAAQ,gBAAgB,gBAAgB;EACxC,GACA;AAEH,QAAO;EACN,GAAG;EACH;EACA;EACA;EACA"}
1
+ {"version":3,"file":"provider.js","names":[],"sources":["../src/provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { normalizeLocale } from \"@cossistant/core\";\nimport type { DefaultMessage, PublicWebsiteResponse } from \"@cossistant/types\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { ConversationTimelineType } from \"@cossistant/types/enums\";\nimport React from \"react\";\nimport { useStoreSelector } from \"./hooks/private/store/use-store-selector\";\nimport { useWebsiteStore } from \"./hooks/private/store/use-website-store\";\nimport { useClient } from \"./hooks/private/use-rest-client\";\nimport { useSeenStore } from \"./realtime/seen-store\";\nimport { WebSocketProvider } from \"./support\";\nimport {\n\tinitializeSupportStore,\n\tuseSupportStore,\n} from \"./support/store/support-store\";\n\nexport type SupportProviderProps = {\n\tchildren: React.ReactNode;\n\tdefaultOpen?: boolean;\n\tapiUrl?: string;\n\twsUrl?: string;\n\tpublicKey?: string;\n\tdefaultMessages?: DefaultMessage[];\n\tquickOptions?: string[];\n\tautoConnect?: boolean;\n\tonWsConnect?: () => void;\n\tonWsDisconnect?: () => void;\n\tonWsError?: (error: Error) => void;\n\tsize?: \"normal\" | \"larger\";\n};\n\nexport type CossistantProviderProps = SupportProviderProps;\n\nexport type CossistantContextValue = {\n\twebsite: PublicWebsiteResponse | null;\n\tdefaultMessages: DefaultMessage[];\n\tquickOptions: string[];\n\tsetDefaultMessages: (messages: DefaultMessage[]) => void;\n\tsetQuickOptions: (options: string[]) => void;\n\tunreadCount: number;\n\tsetUnreadCount: (count: number) => void;\n\tisLoading: boolean;\n\terror: Error | null;\n\tclient: CossistantClient;\n\tisOpen: boolean;\n\topen: () => void;\n\tclose: () => void;\n\ttoggle: () => void;\n};\n\ntype WebsiteData = NonNullable<CossistantContextValue[\"website\"]>;\n\ntype VisitorWithLocale = WebsiteData[\"visitor\"] extends null | undefined\n\t? undefined\n\t: NonNullable<WebsiteData[\"visitor\"]> & { locale: string | null };\n\ntype ConversationSnapshot = {\n\tid: string;\n\tlastTimelineItem: TimelineItem | null;\n};\n\nfunction areConversationSnapshotsEqual(\n\ta: ConversationSnapshot[],\n\tb: ConversationSnapshot[]\n): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\n\tif (a.length !== b.length) {\n\t\treturn false;\n\t}\n\n\tfor (let index = 0; index < a.length; index += 1) {\n\t\tconst snapshotA = a[index];\n\t\tconst snapshotB = b[index];\n\n\t\tif (!snapshotA) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!snapshotB) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst aLastCreatedAt = snapshotA.lastTimelineItem?.createdAt ?? null;\n\t\tconst bLastCreatedAt = snapshotB.lastTimelineItem?.createdAt ?? null;\n\t\tif (snapshotA.id !== snapshotB.id || aLastCreatedAt !== bLastCreatedAt) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nexport type UseSupportValue = CossistantContextValue & {\n\tavailableHumanAgents: NonNullable<WebsiteData[\"availableHumanAgents\"]> | [];\n\tavailableAIAgents: NonNullable<WebsiteData[\"availableAIAgents\"]> | [];\n\tvisitor?: VisitorWithLocale;\n\tsize: \"normal\" | \"larger\";\n};\n\nexport const SupportContext = React.createContext<\n\tCossistantContextValue | undefined\n>(undefined);\n\n/**\n * Internal implementation that wires the REST client and websocket provider\n * together before exposing the combined context.\n */\nfunction SupportProviderInner({\n\tchildren,\n\tapiUrl,\n\twsUrl,\n\tpublicKey,\n\tdefaultMessages,\n\tquickOptions,\n\tautoConnect,\n\tonWsConnect,\n\tonWsDisconnect,\n\tonWsError,\n\tsize = \"normal\",\n\tdefaultOpen = false,\n}: SupportProviderProps) {\n\tconst [unreadCount, setUnreadCount] = React.useState(0);\n\tconst prefetchedVisitorRef = React.useRef<string | null>(null);\n\tconst [_defaultMessages, _setDefaultMessages] = React.useState<\n\t\tDefaultMessage[]\n\t>(defaultMessages ?? []);\n\tconst [_quickOptions, _setQuickOptions] = React.useState<string[]>(\n\t\tquickOptions ?? []\n\t);\n\n\t// Initialize support store with configuration\n\tReact.useEffect(() => {\n\t\tinitializeSupportStore({ size, defaultOpen });\n\t}, [size, defaultOpen]);\n\n\t// Get support store state and actions\n\tconst { config, open, close, toggle } = useSupportStore();\n\n\t// Update state when props change (for initial values from provider)\n\tReact.useEffect(() => {\n\t\tif (defaultMessages?.length) {\n\t\t\t_setDefaultMessages(defaultMessages);\n\t\t}\n\t}, [defaultMessages]);\n\n\tReact.useEffect(() => {\n\t\tif (quickOptions?.length) {\n\t\t\t_setQuickOptions(quickOptions);\n\t\t}\n\t}, [quickOptions]);\n\n\tconst { client } = useClient(publicKey, apiUrl, wsUrl);\n\tconst { website, isLoading, error: websiteError } = useWebsiteStore(client);\n\tconst isVisitorBlocked = website?.visitor?.isBlocked ?? false;\n\tconst visitorId = website?.visitor?.id ?? null;\n\n\tconst seenEntriesByConversation = useSeenStore(\n\t\tReact.useCallback((state) => state.conversations, [])\n\t);\n\n\tconst conversationSnapshots = useStoreSelector(\n\t\tclient.conversationsStore,\n\t\tReact.useCallback(\n\t\t\t(state) =>\n\t\t\t\tstate.ids\n\t\t\t\t\t.map((id) => {\n\t\t\t\t\t\tconst conversation = state.byId[id];\n\n\t\t\t\t\t\tif (!conversation) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tid: conversation.id,\n\t\t\t\t\t\t\tlastTimelineItem: conversation.lastTimelineItem ?? null,\n\t\t\t\t\t\t} satisfies ConversationSnapshot;\n\t\t\t\t\t})\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t(snapshot): snapshot is ConversationSnapshot => snapshot !== null\n\t\t\t\t\t),\n\t\t\t[]\n\t\t),\n\t\tareConversationSnapshotsEqual\n\t);\n\n\tconst derivedUnreadCount = React.useMemo(() => {\n\t\tif (!visitorId) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tlet count = 0;\n\n\t\tfor (const {\n\t\t\tid: conversationId,\n\t\t\tlastTimelineItem,\n\t\t} of conversationSnapshots) {\n\t\t\tif (!lastTimelineItem) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (lastTimelineItem.type !== ConversationTimelineType.MESSAGE) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tlastTimelineItem.visitorId &&\n\t\t\t\tlastTimelineItem.visitorId === visitorId\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst createdAtTime = Date.parse(lastTimelineItem.createdAt);\n\n\t\t\tif (Number.isNaN(createdAtTime)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst seenEntries = seenEntriesByConversation[conversationId];\n\n\t\t\tif (seenEntries) {\n\t\t\t\tconst visitorSeenEntry = Object.values(seenEntries).find(\n\t\t\t\t\t(entry) =>\n\t\t\t\t\t\tentry.actorType === \"visitor\" && entry.actorId === visitorId\n\t\t\t\t);\n\n\t\t\t\tif (visitorSeenEntry) {\n\t\t\t\t\tconst lastSeenTime = Date.parse(visitorSeenEntry.lastSeenAt);\n\n\t\t\t\t\tif (!Number.isNaN(lastSeenTime) && createdAtTime <= lastSeenTime) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcount += 1;\n\t\t}\n\n\t\treturn count;\n\t}, [conversationSnapshots, seenEntriesByConversation, visitorId]);\n\n\tReact.useEffect(() => {\n\t\tsetUnreadCount(derivedUnreadCount);\n\t}, [derivedUnreadCount, setUnreadCount]);\n\n\t// Prime REST client with website/visitor context so headers are sent reliably\n\tReact.useEffect(() => {\n\t\tif (!website) {\n\t\t\treturn;\n\t\t}\n\n\t\tclient.setWebsiteContext(website.id, website.visitor?.id ?? undefined);\n\t}, [client, website]);\n\n\tReact.useEffect(() => {\n\t\tif (isVisitorBlocked) {\n\t\t\tprefetchedVisitorRef.current = null;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!autoConnect) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!website) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!visitorId) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (prefetchedVisitorRef.current === visitorId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasExistingConversations =\n\t\t\tclient.conversationsStore.getState().ids.length > 0;\n\n\t\tprefetchedVisitorRef.current = visitorId;\n\n\t\tif (hasExistingConversations) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid client.listConversations().catch((err) => {\n\t\t\tconsole.error(\"[SupportProvider] Failed to prefetch conversations\", err);\n\t\t\tprefetchedVisitorRef.current = null;\n\t\t});\n\t}, [autoConnect, client, isVisitorBlocked, visitorId, website]);\n\n\tconst error = websiteError;\n\n\tReact.useEffect(() => {\n\t\tclient.setVisitorBlocked(isVisitorBlocked);\n\t}, [client, isVisitorBlocked]);\n\n\tconst setDefaultMessages = React.useCallback((messages: DefaultMessage[]) => {\n\t\t_setDefaultMessages(messages);\n\t}, []);\n\n\tconst setQuickOptions = React.useCallback((options: string[]) => {\n\t\t_setQuickOptions(options);\n\t}, []);\n\n\tconst value = React.useMemo<CossistantContextValue>(\n\t\t() => ({\n\t\t\twebsite,\n\t\t\tunreadCount,\n\t\t\tsetUnreadCount,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tclient,\n\t\t\tdefaultMessages: _defaultMessages,\n\t\t\tsetDefaultMessages,\n\t\t\tquickOptions: _quickOptions,\n\t\t\tsetQuickOptions,\n\t\t\tisOpen: config.isOpen,\n\t\t\topen,\n\t\t\tclose,\n\t\t\ttoggle,\n\t\t}),\n\t\t[\n\t\t\twebsite,\n\t\t\tunreadCount,\n\t\t\tisLoading,\n\t\t\terror,\n\t\t\tclient,\n\t\t\t_defaultMessages,\n\t\t\t_quickOptions,\n\t\t\tsetDefaultMessages,\n\t\t\tsetQuickOptions,\n\t\t\tconfig.isOpen,\n\t\t\topen,\n\t\t\tclose,\n\t\t\ttoggle,\n\t\t]\n\t);\n\n\tconst webSocketKey = React.useMemo(() => {\n\t\tif (!website) {\n\t\t\treturn \"no-website\";\n\t\t}\n\n\t\tconst visitorKey = website.visitor?.id ?? \"anonymous\";\n\t\tconst blockedState = isVisitorBlocked ? \"blocked\" : \"active\";\n\n\t\treturn `${website.id}:${visitorKey}:${blockedState}`;\n\t}, [isVisitorBlocked, website]);\n\n\treturn (\n\t\t<SupportContext.Provider value={value}>\n\t\t\t<WebSocketProvider\n\t\t\t\tautoConnect={autoConnect && !isVisitorBlocked}\n\t\t\t\tkey={webSocketKey}\n\t\t\t\tonConnect={onWsConnect}\n\t\t\t\tonDisconnect={onWsDisconnect}\n\t\t\t\tonError={onWsError}\n\t\t\t\tpublicKey={publicKey}\n\t\t\t\tvisitorId={isVisitorBlocked ? undefined : website?.visitor?.id}\n\t\t\t\twebsiteId={website?.id}\n\t\t\t\twsUrl={wsUrl}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</WebSocketProvider>\n\t\t</SupportContext.Provider>\n\t);\n}\n\n/**\n * Hosts the entire customer support widget ecosystem by handing out context\n * about the current website, visitor, unread counts, realtime subscriptions\n * and the REST client. Provide your Cossistant public key plus optional\n * defaults to configure the widget behaviour.\n */\nexport function SupportProvider({\n\tchildren,\n\tapiUrl = \"https://api.cossistant.com/v1\",\n\twsUrl = \"wss://api.cossistant.com/ws\",\n\tpublicKey,\n\tdefaultMessages,\n\tquickOptions,\n\tautoConnect = true,\n\tonWsConnect,\n\tonWsDisconnect,\n\tonWsError,\n\tsize = \"normal\",\n\tdefaultOpen = false,\n}: SupportProviderProps): React.ReactElement {\n\treturn (\n\t\t<SupportProviderInner\n\t\t\tapiUrl={apiUrl}\n\t\t\tautoConnect={autoConnect}\n\t\t\tdefaultMessages={defaultMessages}\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tonWsConnect={onWsConnect}\n\t\t\tonWsDisconnect={onWsDisconnect}\n\t\t\tonWsError={onWsError}\n\t\t\tpublicKey={publicKey}\n\t\t\tquickOptions={quickOptions}\n\t\t\tsize={size}\n\t\t\twsUrl={wsUrl}\n\t\t>\n\t\t\t{children}\n\t\t</SupportProviderInner>\n\t);\n}\n\n/**\n * Convenience hook that exposes the aggregated support context. Throws when it\n * is consumed outside of `SupportProvider` to catch integration mistakes.\n */\nexport function useSupport(): UseSupportValue {\n\tconst context = React.useContext(SupportContext);\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"useSupport must be used within a cossistant SupportProvider\"\n\t\t);\n\t}\n\n\tconst availableHumanAgents = context.website?.availableHumanAgents || [];\n\tconst availableAIAgents = context.website?.availableAIAgents || [];\n\tconst visitorLanguage = context.website?.visitor?.language || null;\n\n\t// Get additional config from support store\n\tconst { config } = useSupportStore();\n\n\t// Create visitor object with normalized locale\n\tconst visitor = context.website?.visitor\n\t\t? {\n\t\t\t\t...context.website.visitor,\n\t\t\t\tlocale: normalizeLocale(visitorLanguage),\n\t\t\t}\n\t\t: undefined;\n\n\treturn {\n\t\t...context,\n\t\tavailableHumanAgents,\n\t\tavailableAIAgents,\n\t\tvisitor,\n\t\tsize: config.size,\n\t};\n}\n"],"mappings":"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"}
@@ -2,6 +2,10 @@ import { AnyRealtimeEvent } from "../realtime-events.js";
2
2
 
3
3
  //#region src/realtime/event-filter.d.ts
4
4
  declare function getTargetVisitorId(event: AnyRealtimeEvent): string | null;
5
+ /**
6
+ * Determines whether a realtime event should be processed based on website and
7
+ * visitor identifiers.
8
+ */
5
9
  declare function shouldDeliverEvent(event: AnyRealtimeEvent, websiteId: string | null, visitorId: string | null): boolean;
6
10
  //#endregion
7
11
  export { getTargetVisitorId, shouldDeliverEvent };
@@ -1 +1 @@
1
- {"version":3,"file":"event-filter.d.ts","names":[],"sources":["../../src/realtime/event-filter.ts"],"sourcesContent":[],"mappings":";;;iBAES,kBAAA,QAA0B;iBAkBnB,kBAAA,QACR"}
1
+ {"version":3,"file":"event-filter.d.ts","names":[],"sources":["../../src/realtime/event-filter.ts"],"sourcesContent":[],"mappings":";;;iBAES,kBAAA,QAA0B;;AAFuC;AAwB1E;;iBAAgB,kBAAA,QACR"}
@@ -8,6 +8,10 @@ function getTargetVisitorId(event) {
8
8
  }
9
9
  return null;
10
10
  }
11
+ /**
12
+ * Determines whether a realtime event should be processed based on website and
13
+ * visitor identifiers.
14
+ */
11
15
  function shouldDeliverEvent(event, websiteId, visitorId) {
12
16
  if (websiteId && event.payload.websiteId !== websiteId) return false;
13
17
  if (!visitorId) return true;
@@ -1 +1 @@
1
- {"version":3,"file":"event-filter.js","names":[],"sources":["../../src/realtime/event-filter.ts"],"sourcesContent":["import type { AnyRealtimeEvent } from \"@cossistant/types/realtime-events\";\n\nfunction getTargetVisitorId(event: AnyRealtimeEvent): string | null {\n\tconst payloadVisitorId = event.payload.visitorId;\n\n\tif (typeof payloadVisitorId === \"string\" && payloadVisitorId.length > 0) {\n\t\treturn payloadVisitorId;\n\t}\n\n\tif (event.type === \"timelineItemCreated\") {\n\t\tconst itemVisitorId = event.payload.item.visitorId;\n\n\t\tif (typeof itemVisitorId === \"string\" && itemVisitorId.length > 0) {\n\t\t\treturn itemVisitorId;\n\t\t}\n\t}\n\n\treturn null;\n}\n\nexport function shouldDeliverEvent(\n\tevent: AnyRealtimeEvent,\n\twebsiteId: string | null,\n\tvisitorId: string | null\n): boolean {\n\tif (websiteId && event.payload.websiteId !== websiteId) {\n\t\treturn false;\n\t}\n\n\tif (!visitorId) {\n\t\treturn true;\n\t}\n\n\tconst targetVisitorId = getTargetVisitorId(event);\n\n\tif (targetVisitorId && targetVisitorId !== visitorId) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nexport { getTargetVisitorId };\n"],"mappings":";AAEA,SAAS,mBAAmB,OAAwC;CACnE,MAAM,mBAAmB,MAAM,QAAQ;AAEvC,KAAI,OAAO,qBAAqB,YAAY,iBAAiB,SAAS,EACrE,QAAO;AAGR,KAAI,MAAM,SAAS,uBAAuB;EACzC,MAAM,gBAAgB,MAAM,QAAQ,KAAK;AAEzC,MAAI,OAAO,kBAAkB,YAAY,cAAc,SAAS,EAC/D,QAAO;;AAIT,QAAO;;AAGR,SAAgB,mBACf,OACA,WACA,WACU;AACV,KAAI,aAAa,MAAM,QAAQ,cAAc,UAC5C,QAAO;AAGR,KAAI,CAAC,UACJ,QAAO;CAGR,MAAM,kBAAkB,mBAAmB,MAAM;AAEjD,KAAI,mBAAmB,oBAAoB,UAC1C,QAAO;AAGR,QAAO"}
1
+ {"version":3,"file":"event-filter.js","names":[],"sources":["../../src/realtime/event-filter.ts"],"sourcesContent":["import type { AnyRealtimeEvent } from \"@cossistant/types/realtime-events\";\n\nfunction getTargetVisitorId(event: AnyRealtimeEvent): string | null {\n\tconst payloadVisitorId = event.payload.visitorId;\n\n\tif (typeof payloadVisitorId === \"string\" && payloadVisitorId.length > 0) {\n\t\treturn payloadVisitorId;\n\t}\n\n\tif (event.type === \"timelineItemCreated\") {\n\t\tconst itemVisitorId = event.payload.item.visitorId;\n\n\t\tif (typeof itemVisitorId === \"string\" && itemVisitorId.length > 0) {\n\t\t\treturn itemVisitorId;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Determines whether a realtime event should be processed based on website and\n * visitor identifiers.\n */\nexport function shouldDeliverEvent(\n\tevent: AnyRealtimeEvent,\n\twebsiteId: string | null,\n\tvisitorId: string | null\n): boolean {\n\tif (websiteId && event.payload.websiteId !== websiteId) {\n\t\treturn false;\n\t}\n\n\tif (!visitorId) {\n\t\treturn true;\n\t}\n\n\tconst targetVisitorId = getTargetVisitorId(event);\n\n\tif (targetVisitorId && targetVisitorId !== visitorId) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nexport { getTargetVisitorId };\n"],"mappings":";AAEA,SAAS,mBAAmB,OAAwC;CACnE,MAAM,mBAAmB,MAAM,QAAQ;AAEvC,KAAI,OAAO,qBAAqB,YAAY,iBAAiB,SAAS,EACrE,QAAO;AAGR,KAAI,MAAM,SAAS,uBAAuB;EACzC,MAAM,gBAAgB,MAAM,QAAQ,KAAK;AAEzC,MAAI,OAAO,kBAAkB,YAAY,cAAc,SAAS,EAC/D,QAAO;;AAIT,QAAO;;;;;;AAOR,SAAgB,mBACf,OACA,WACA,WACU;AACV,KAAI,aAAa,MAAM,QAAQ,cAAc,UAC5C,QAAO;AAGR,KAAI,CAAC,UACJ,QAAO;CAGR,MAAM,kBAAkB,mBAAmB,MAAM;AAEjD,KAAI,mBAAmB,oBAAoB,UAC1C,QAAO;AAGR,QAAO"}
package/realtime/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { RealtimeProvider, useRealtimeConnection } from "./provider.js";
2
1
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./seen-store.js";
2
+ import { RealtimeProvider, useRealtimeConnection } from "./provider.js";
3
3
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./typing-store.js";
4
4
  import { useRealtime } from "./use-realtime.js";
5
5
  import { SupportRealtimeProvider } from "./support-provider.js";
@@ -1,6 +1,5 @@
1
1
  import { AnyRealtimeEvent, RealtimeEvent } from "../realtime-events.js";
2
2
  import React from "react";
3
- import * as react_jsx_runtime0 from "react/jsx-runtime";
4
3
 
5
4
  //#region src/realtime/provider.d.ts
6
5
  type SubscribeHandler = (event: AnyRealtimeEvent) => void;
@@ -42,6 +41,9 @@ type RealtimeContextValue = RealtimeConnectionState & {
42
41
  websiteId: string | null;
43
42
  userId: string | null;
44
43
  };
44
+ /**
45
+ * Provides websocket connectivity and heartbeating logic for realtime events.
46
+ */
45
47
  declare function RealtimeProvider({
46
48
  children,
47
49
  wsUrl,
@@ -50,7 +52,10 @@ declare function RealtimeProvider({
50
52
  onConnect,
51
53
  onDisconnect,
52
54
  onError
53
- }: RealtimeProviderProps): react_jsx_runtime0.JSX.Element;
55
+ }: RealtimeProviderProps): React.ReactElement;
56
+ /**
57
+ * Returns the realtime connection context.
58
+ */
54
59
  declare function useRealtimeConnection(): RealtimeContextValue;
55
60
  //#endregion
56
61
  export { type RealtimeAuthConfig, type RealtimeContextValue, type RealtimeEvent, RealtimeProvider, type RealtimeProviderProps, useRealtimeConnection };
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/realtime/provider.tsx"],"sourcesContent":[],"mappings":";;;;;KAuBK,gBAAA,WAA2B;KA+B3B,iBAAA;;EA/BA,SAAA,EAAA,MAAA,GAAgB,IAAA;EA+BhB,SAAA,CAAA,EAAA,MAAA,GAAiB,IAAA;EAOjB,SAAA,CAAA,EAAA,MAAA,GAAiB,IAAA;AAAA,CAAA;KAAjB,iBAAA,GAOkB;MAAG,EAAA,SAAA;cAAoB,EAAA,MAAA,GAAA,IAAA;EAAiB,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAW1D,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;CAAqB;KAXrB,kBAAA,GAAqB,iBAYT,GAZ6B,iBAY7B;KADZ,qBAAA,GAGE;UAIY,EANR,KAAA,CAAM,SAME;EAAK,KAAA,CAAA,EAAA,MAAA;EAGnB,IAAA,EAPE,kBAOF,GAAuB,IAAA;EAAA,WAAA,CAAA,EAAA,OAAA;WAGpB,CAAA,EAAA,GAAA,GAAA,IAAA;cACO,CAAA,EAAA,GAAA,GAAA,IAAA;SAEO,CAAA,EAAA,CAAA,KAAA,EATH,KASG,EAAA,GAAA,IAAA;;KANjB,uBAAA,GAOuB;EAKvB,WAAA,EAAA,OAAA;EA2QW,YAAA,EAAA,OAAgB;EAAA,KAAA,EApRxB,KAoRwB,GAAA,IAAA;MAC/B,EAAA,CAAA,KAAA,EApRc,gBAoRd,EAAA,GAAA,IAAA;SACA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;WACA,EAAA,CAAA,OAAA,EApRqB,gBAoRrB,EAAA,GAAA,GAAA,GAAA,IAAA;WACA,EApRW,gBAoRX,GAAA,IAAA;cACA,EAAA,MAAA,GAAA,IAAA;WACA,EAAA,GAAA,GAAA,IAAA;;KAjRI,oBAAA,GAAuB,uBAmRzB,GAAA;WAAqB,EAAA,MAAA,GAAA,IAAA;EAAA,SAAA,EAAA,MAAA,GAAA,IAAA;EAmPR,MAAA,EAAA,MAAA,GAAA,IAAA;;iBA3PA,gBAAA;;;;;;;;GAQb,wBAAqB,kBAAA,CAAA,GAAA,CAAA;iBAmPR,qBAAA,CAAA,GAAyB"}
1
+ {"version":3,"file":"provider.d.ts","names":[],"sources":["../../src/realtime/provider.tsx"],"sourcesContent":[],"mappings":";;;;KAuBK,gBAAA,WAA2B;KA+B3B,iBAAA;EA/BA,IAAA,EAAA,SAAA;EA+BA,SAAA,EAAA,MAAA,GAAiB,IAAA;EAOjB,SAAA,CAAA,EAAA,MAAA,GAAiB,IAAA;EAOjB,SAAA,CAAA,EAAA,MAAA,GAAkB,IAAA;AAAwC,CAAA;KAP1D,iBAAA,GAmBY;EAEV,IAAA,EAAA,SAAA;EAIY,YAAA,EAAA,MAAA,GAAA,IAAA;EAAK,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAGnB,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;CAGG;KAxBH,kBAAA,GAAqB,iBAyBX,GAzB+B,iBAyB/B;KAdV,qBAAA,GAgBiB;EACV,QAAA,EAhBD,KAAA,CAAM,SAgBL;EAAgB,KAAA,CAAA,EAAA,MAAA;EAKvB,IAAA,EAnBE,kBAmBkB,GAAA,IAAA;EA8QT,WAAA,CAAA,EAAA,OAAgB;EAC/B,SAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EACA,YAAA,CAAA,EAAA,GAAA,GAAA,IAAA;EACA,OAAA,CAAA,EAAA,CAAA,KAAA,EAhSkB,KAgSlB,EAAA,GAAA,IAAA;CACA;KA9RI,uBAAA,GA+RJ;EACA,WAAA,EAAA,OAAA;EACA,YAAA,EAAA,OAAA;EACE,KAAA,EA/RK,KA+RL,GAAA,IAAA;EAAwB,IAAM,EAAA,CAAA,KAAA,EA9RlB,gBA8RkB,EAAA,GAAA,IAAA;EAAY,OAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EA6S7B,SAAA,EAAA,CAAA,OAAA,EAzkBM,gBAykBmB,EAAA,GAAA,GAAA,GAAA,IAAA;aAxkB7B;;;;KAKP,oBAAA,GAAuB;;;;;;;;iBA8QZ,gBAAA;;;;;;;;GAQb,wBAAwB,KAAA,CAAM;;;;iBA6SjB,qBAAA,CAAA,GAAyB"}
@@ -2,9 +2,9 @@
2
2
 
3
3
 
4
4
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
5
- import { jsx } from "react/jsx-runtime";
6
5
  import { isValidEventType, validateRealtimeEvent } from "@cossistant/types/realtime-events";
7
6
  import useWebSocket, { ReadyState } from "react-use-websocket";
7
+ import { jsx } from "react/jsx-runtime";
8
8
 
9
9
  //#region src/realtime/provider.tsx
10
10
  const DEFAULT_HEARTBEAT_INTERVAL_MS = 15e3;
@@ -180,11 +180,16 @@ function buildSocketUrl(baseUrl, auth) {
180
180
  return null;
181
181
  }
182
182
  }
183
+ /**
184
+ * Provides websocket connectivity and heartbeating logic for realtime events.
185
+ */
183
186
  function RealtimeProvider({ children, wsUrl = DEFAULT_WS_URL, auth, autoConnect = true, onConnect, onDisconnect, onError }) {
184
187
  const normalizedAuth = normalizeAuth(auth);
185
188
  const socketUrl = buildSocketUrl(wsUrl, normalizedAuth);
186
189
  const eventHandlersRef = useRef(/* @__PURE__ */ new Set());
187
190
  const lastHeartbeatRef = useRef(Date.now());
191
+ const hasOpenedRef = useRef(false);
192
+ const previousUrlRef = useRef(null);
188
193
  const [connectionError, setConnectionError] = useState(null);
189
194
  const [lastEvent, setLastEvent] = useState(null);
190
195
  const [connectionId, setConnectionId] = useState(null);
@@ -192,6 +197,12 @@ function RealtimeProvider({ children, wsUrl = DEFAULT_WS_URL, auth, autoConnect
192
197
  const heartbeatTimeoutMs = DEFAULT_HEARTBEAT_TIMEOUT_MS;
193
198
  const canConnect = Boolean(autoConnect && socketUrl);
194
199
  const connectionUrl = canConnect ? socketUrl : null;
200
+ useEffect(() => {
201
+ if (connectionUrl !== previousUrlRef.current) {
202
+ previousUrlRef.current = connectionUrl;
203
+ hasOpenedRef.current = false;
204
+ }
205
+ }, [connectionUrl]);
195
206
  const { sendMessage, sendJsonMessage, lastMessage, readyState, getWebSocket } = useWebSocket(connectionUrl, {
196
207
  shouldReconnect: (closeEvent) => {
197
208
  if (!canConnect) return false;
@@ -210,6 +221,7 @@ function RealtimeProvider({ children, wsUrl = DEFAULT_WS_URL, auth, autoConnect
210
221
  },
211
222
  retryOnError: false,
212
223
  onOpen: () => {
224
+ hasOpenedRef.current = true;
213
225
  setConnectionError(null);
214
226
  lastHeartbeatRef.current = Date.now();
215
227
  onConnect?.();
@@ -219,6 +231,13 @@ function RealtimeProvider({ children, wsUrl = DEFAULT_WS_URL, auth, autoConnect
219
231
  onDisconnect?.();
220
232
  },
221
233
  onError: (event) => {
234
+ if (!canConnect) return;
235
+ const socketLike = event.target;
236
+ const currentSocket = getWebSocket();
237
+ const socketState = typeof WebSocket !== "undefined" && socketLike instanceof WebSocket ? socketLike.readyState : void 0;
238
+ const isThisProvidersSocket = currentSocket === socketLike;
239
+ if (!isThisProvidersSocket && currentSocket || !connectionUrl || isThisProvidersSocket && !hasOpenedRef.current && (socketState === WebSocket.CLOSING || socketState === WebSocket.CLOSED)) return;
240
+ if (isThisProvidersSocket && !hasOpenedRef.current && socketState === WebSocket.CONNECTING && connectionUrl !== previousUrlRef.current) return;
222
241
  const err = /* @__PURE__ */ new Error(`WebSocket error: ${event.type}`);
223
242
  setConnectionError(err);
224
243
  onError?.(err);
@@ -340,6 +359,9 @@ function RealtimeProvider({ children, wsUrl = DEFAULT_WS_URL, auth, autoConnect
340
359
  children
341
360
  });
342
361
  }
362
+ /**
363
+ * Returns the realtime connection context.
364
+ */
343
365
  function useRealtimeConnection() {
344
366
  const context = useContext(RealtimeContext);
345
367
  if (!context) throw new Error("useRealtimeConnection must be used within RealtimeProvider");