@cossistant/react 0.0.19 → 0.0.22

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 (101) hide show
  1. package/conversation.d.ts +28 -0
  2. package/conversation.d.ts.map +1 -1
  3. package/hooks/index.d.ts +4 -1
  4. package/hooks/index.js +4 -1
  5. package/hooks/private/use-default-messages.js +1 -1
  6. package/hooks/private/use-default-messages.js.map +1 -1
  7. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  8. package/hooks/private/use-grouped-messages.js +4 -18
  9. package/hooks/private/use-grouped-messages.js.map +1 -1
  10. package/hooks/private/use-rest-client.js +1 -1
  11. package/hooks/private/use-rest-client.js.map +1 -1
  12. package/hooks/private/use-visitor-typing-reporter.js +3 -3
  13. package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
  14. package/hooks/use-conversation-auto-seen.d.ts +1 -1
  15. package/hooks/use-conversation-auto-seen.js +30 -46
  16. package/hooks/use-conversation-auto-seen.js.map +1 -1
  17. package/hooks/use-conversation-page.js +1 -1
  18. package/hooks/use-conversation-page.js.map +1 -1
  19. package/hooks/use-conversation-seen.d.ts.map +1 -1
  20. package/hooks/use-conversation-seen.js +7 -3
  21. package/hooks/use-conversation-seen.js.map +1 -1
  22. package/hooks/use-new-message-sound.d.ts +23 -0
  23. package/hooks/use-new-message-sound.d.ts.map +1 -0
  24. package/hooks/use-new-message-sound.js +34 -0
  25. package/hooks/use-new-message-sound.js.map +1 -0
  26. package/hooks/use-send-message.js +1 -1
  27. package/hooks/use-send-message.js.map +1 -1
  28. package/hooks/use-sound-effect.d.ts +30 -0
  29. package/hooks/use-sound-effect.d.ts.map +1 -0
  30. package/hooks/use-sound-effect.js +104 -0
  31. package/hooks/use-sound-effect.js.map +1 -0
  32. package/hooks/use-typing-sound.d.ts +18 -0
  33. package/hooks/use-typing-sound.d.ts.map +1 -0
  34. package/hooks/use-typing-sound.js +38 -0
  35. package/hooks/use-typing-sound.js.map +1 -0
  36. package/index.d.ts +5 -2
  37. package/index.js +8 -6
  38. package/package.json +3 -3
  39. package/primitives/avatar/image.d.ts +1 -1
  40. package/primitives/bubble.js +1 -1
  41. package/primitives/index.d.ts +3 -5
  42. package/primitives/index.js +3 -9
  43. package/primitives/index.parts.d.ts +2 -4
  44. package/primitives/index.parts.js +2 -4
  45. package/primitives/router.d.ts +19 -20
  46. package/primitives/router.d.ts.map +1 -1
  47. package/primitives/router.js +17 -11
  48. package/primitives/router.js.map +1 -1
  49. package/realtime/index.js +1 -1
  50. package/realtime/provider.d.ts +1 -0
  51. package/realtime/provider.d.ts.map +1 -1
  52. package/realtime/provider.js +59 -10
  53. package/realtime/provider.js.map +1 -1
  54. package/realtime-events.d.ts +14 -0
  55. package/realtime-events.d.ts.map +1 -1
  56. package/schemas3.d.ts +7 -0
  57. package/schemas3.d.ts.map +1 -1
  58. package/support/components/bubble.d.ts.map +1 -1
  59. package/support/components/bubble.js +27 -4
  60. package/support/components/bubble.js.map +1 -1
  61. package/support/components/conversation-event.js +1 -1
  62. package/support/components/conversation-event.js.map +1 -1
  63. package/support/components/conversation-timeline.d.ts.map +1 -1
  64. package/support/components/conversation-timeline.js +5 -0
  65. package/support/components/conversation-timeline.js.map +1 -1
  66. package/support/components/support-content.d.ts +2 -0
  67. package/support/components/support-content.d.ts.map +1 -1
  68. package/support/components/support-content.js +5 -2
  69. package/support/components/support-content.js.map +1 -1
  70. package/support/components/timeline-message-group.js +2 -2
  71. package/support/components/timeline-message-group.js.map +1 -1
  72. package/support/components/timeline-message-item.js +2 -2
  73. package/support/components/timeline-message-item.js.map +1 -1
  74. package/support/components/typing-indicator.d.ts.map +1 -1
  75. package/support/index.d.ts +12 -7
  76. package/support/index.d.ts.map +1 -1
  77. package/support/index.js +28 -29
  78. package/support/index.js.map +1 -1
  79. package/support/pages/conversation.d.ts.map +1 -1
  80. package/support/pages/conversation.js +19 -1
  81. package/support/pages/conversation.js.map +1 -1
  82. package/support/router.d.ts +19 -9
  83. package/support/router.d.ts.map +1 -1
  84. package/support/router.js +31 -30
  85. package/support/router.js.map +1 -1
  86. package/support/text/runtime.js +1 -1
  87. package/support/text/runtime.js.map +1 -1
  88. package/support/utils/time.d.ts +1 -0
  89. package/support/utils/time.d.ts.map +1 -1
  90. package/support/utils/time.js +2 -0
  91. package/support/utils/time.js.map +1 -1
  92. package/timeline-item.d.ts +14 -0
  93. package/timeline-item.d.ts.map +1 -1
  94. package/primitives/page-registry.d.ts +0 -30
  95. package/primitives/page-registry.d.ts.map +0 -1
  96. package/primitives/page-registry.js +0 -45
  97. package/primitives/page-registry.js.map +0 -1
  98. package/primitives/page.d.ts +0 -21
  99. package/primitives/page.d.ts.map +0 -1
  100. package/primitives/page.js +0 -18
  101. package/primitives/page.js.map +0 -1
@@ -13,12 +13,16 @@ function useConversationSeen(conversationId, options = {}) {
13
13
  const { initialData } = options;
14
14
  const hydratedKeyRef = useRef(null);
15
15
  useEffect(() => {
16
- if (!(conversationId && initialData) || initialData.length === 0) return;
17
- const hydrationKey = `${conversationId}:${initialData.map((entry) => `${entry.id}:${new Date(entry.updatedAt).getTime()}`).join("|")}`;
16
+ if (!conversationId) {
17
+ hydratedKeyRef.current = null;
18
+ return;
19
+ }
20
+ if (!initialData || initialData.length === 0) return;
21
+ const hydrationKey = conversationId;
18
22
  if (hydratedKeyRef.current === hydrationKey) return;
19
23
  hydrateConversationSeen(conversationId, initialData);
20
24
  hydratedKeyRef.current = hydrationKey;
21
- }, [conversationId, initialData]);
25
+ }, [conversationId]);
22
26
  const conversationSeen = useSeenStore((state) => conversationId ? state.conversations[conversationId] ?? null : null);
23
27
  return useMemo(() => {
24
28
  if (!(conversationId && conversationSeen)) return [];
@@ -1 +1 @@
1
- {"version":3,"file":"use-conversation-seen.js","names":[],"sources":["../../src/hooks/use-conversation-seen.ts"],"sourcesContent":["import type { ConversationSeen } from \"@cossistant/types/schemas\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { hydrateConversationSeen, useSeenStore } from \"../realtime/seen-store\";\n\ntype UseConversationSeenOptions = {\n\tinitialData?: ConversationSeen[];\n};\n\nfunction buildSeenId(\n\tconversationId: string,\n\tactorType: string,\n\tactorId: string\n) {\n\treturn `${conversationId}-${actorType}-${actorId}`;\n}\n\n/**\n * Reads the conversation seen store and optionally hydrates it with SSR\n * payloads.\n */\nexport function useConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {}\n): ConversationSeen[] {\n\tconst { initialData } = options;\n\tconst hydratedKeyRef = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\tif (!(conversationId && initialData) || initialData.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hydrationKey = `${conversationId}:${initialData\n\t\t\t.map((entry) => `${entry.id}:${new Date(entry.updatedAt).getTime()}`)\n\t\t\t.join(\"|\")}`;\n\n\t\tif (hydratedKeyRef.current === hydrationKey) {\n\t\t\treturn;\n\t\t}\n\n\t\thydrateConversationSeen(conversationId, initialData);\n\t\thydratedKeyRef.current = hydrationKey;\n\t}, [conversationId, initialData]);\n\n\tconst conversationSeen = useSeenStore((state) =>\n\t\tconversationId ? (state.conversations[conversationId] ?? null) : null\n\t);\n\n\treturn useMemo(() => {\n\t\tif (!(conversationId && conversationSeen)) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn Object.values(conversationSeen).map(\n\t\t\t(entry) =>\n\t\t\t\t({\n\t\t\t\t\tid: buildSeenId(conversationId, entry.actorType, entry.actorId),\n\t\t\t\t\tconversationId,\n\t\t\t\t\tuserId: entry.actorType === \"user\" ? entry.actorId : null,\n\t\t\t\t\tvisitorId: entry.actorType === \"visitor\" ? entry.actorId : null,\n\t\t\t\t\taiAgentId: entry.actorType === \"ai_agent\" ? entry.actorId : null,\n\t\t\t\t\tlastSeenAt: entry.lastSeenAt,\n\t\t\t\t\tcreatedAt: entry.lastSeenAt,\n\t\t\t\t\tupdatedAt: entry.lastSeenAt,\n\t\t\t\t\tdeletedAt: null,\n\t\t\t\t}) satisfies ConversationSeen\n\t\t);\n\t}, [conversationId, conversationSeen]);\n}\n\n/**\n * Debounced version of useConversationSeen that delays updates by 500ms\n * to prevent animation conflicts when messages are sent and immediately seen.\n *\n * Use this in UI components where smooth animations are critical.\n */\nexport function useDebouncedConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {},\n\tdelay = 500\n): ConversationSeen[] {\n\tconst seenData = useConversationSeen(conversationId, options);\n\tconst [debouncedSeenData, setDebouncedSeenData] =\n\t\tuseState<ConversationSeen[]>(seenData);\n\tconst timeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n\tuseEffect(() => {\n\t\t// Clear any pending timeout\n\t\tif (timeoutRef.current) {\n\t\t\tclearTimeout(timeoutRef.current);\n\t\t}\n\n\t\t// Set new timeout to update after delay\n\t\ttimeoutRef.current = setTimeout(() => {\n\t\t\tsetDebouncedSeenData(seenData);\n\t\t}, delay);\n\n\t\t// Cleanup on unmount or when seenData changes\n\t\treturn () => {\n\t\t\tif (timeoutRef.current) {\n\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, [seenData, delay]);\n\n\treturn debouncedSeenData;\n}\n"],"mappings":";;;;AAQA,SAAS,YACR,gBACA,WACA,SACC;AACD,QAAO,GAAG,eAAe,GAAG,UAAU,GAAG;;;;;;AAO1C,SAAgB,oBACf,gBACA,UAAsC,EAAE,EACnB;CACrB,MAAM,EAAE,gBAAgB;CACxB,MAAM,iBAAiB,OAAsB,KAAK;AAElD,iBAAgB;AACf,MAAI,EAAE,kBAAkB,gBAAgB,YAAY,WAAW,EAC9D;EAGD,MAAM,eAAe,GAAG,eAAe,GAAG,YACxC,KAAK,UAAU,GAAG,MAAM,GAAG,GAAG,IAAI,KAAK,MAAM,UAAU,CAAC,SAAS,GAAG,CACpE,KAAK,IAAI;AAEX,MAAI,eAAe,YAAY,aAC9B;AAGD,0BAAwB,gBAAgB,YAAY;AACpD,iBAAe,UAAU;IACvB,CAAC,gBAAgB,YAAY,CAAC;CAEjC,MAAM,mBAAmB,cAAc,UACtC,iBAAkB,MAAM,cAAc,mBAAmB,OAAQ,KACjE;AAED,QAAO,cAAc;AACpB,MAAI,EAAE,kBAAkB,kBACvB,QAAO,EAAE;AAGV,SAAO,OAAO,OAAO,iBAAiB,CAAC,KACrC,WACC;GACA,IAAI,YAAY,gBAAgB,MAAM,WAAW,MAAM,QAAQ;GAC/D;GACA,QAAQ,MAAM,cAAc,SAAS,MAAM,UAAU;GACrD,WAAW,MAAM,cAAc,YAAY,MAAM,UAAU;GAC3D,WAAW,MAAM,cAAc,aAAa,MAAM,UAAU;GAC5D,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW;GACX,EACF;IACC,CAAC,gBAAgB,iBAAiB,CAAC;;;;;;;;AASvC,SAAgB,6BACf,gBACA,UAAsC,EAAE,EACxC,QAAQ,KACa;CACrB,MAAM,WAAW,oBAAoB,gBAAgB,QAAQ;CAC7D,MAAM,CAAC,mBAAmB,wBACzB,SAA6B,SAAS;CACvC,MAAM,aAAa,OAA8B,KAAK;AAEtD,iBAAgB;AAEf,MAAI,WAAW,QACd,cAAa,WAAW,QAAQ;AAIjC,aAAW,UAAU,iBAAiB;AACrC,wBAAqB,SAAS;KAC5B,MAAM;AAGT,eAAa;AACZ,OAAI,WAAW,QACd,cAAa,WAAW,QAAQ;;IAGhC,CAAC,UAAU,MAAM,CAAC;AAErB,QAAO"}
1
+ {"version":3,"file":"use-conversation-seen.js","names":[],"sources":["../../src/hooks/use-conversation-seen.ts"],"sourcesContent":["import type { ConversationSeen } from \"@cossistant/types/schemas\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { hydrateConversationSeen, useSeenStore } from \"../realtime/seen-store\";\n\ntype UseConversationSeenOptions = {\n\tinitialData?: ConversationSeen[];\n};\n\nfunction buildSeenId(\n\tconversationId: string,\n\tactorType: string,\n\tactorId: string\n) {\n\treturn `${conversationId}-${actorType}-${actorId}`;\n}\n\n/**\n * Reads the conversation seen store and optionally hydrates it with SSR\n * payloads.\n */\nexport function useConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {}\n): ConversationSeen[] {\n\tconst { initialData } = options;\n\tconst hydratedKeyRef = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\t// Clear hydration key when conversation changes or is unmounted\n\t\tif (!conversationId) {\n\t\t\thydratedKeyRef.current = null;\n\t\t\treturn;\n\t\t}\n\n\t\t// Skip if no initial data\n\t\tif (!initialData || initialData.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Only hydrate once per conversation\n\t\tconst hydrationKey = conversationId;\n\n\t\tif (hydratedKeyRef.current === hydrationKey) {\n\t\t\treturn; // Already hydrated for this conversation\n\t\t}\n\n\t\thydrateConversationSeen(conversationId, initialData);\n\t\thydratedKeyRef.current = hydrationKey;\n\t}, [conversationId]); // Only depend on conversationId, NOT initialData\n\n\tconst conversationSeen = useSeenStore((state) =>\n\t\tconversationId ? (state.conversations[conversationId] ?? null) : null\n\t);\n\n\treturn useMemo(() => {\n\t\tif (!(conversationId && conversationSeen)) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn Object.values(conversationSeen).map(\n\t\t\t(entry) =>\n\t\t\t\t({\n\t\t\t\t\tid: buildSeenId(conversationId, entry.actorType, entry.actorId),\n\t\t\t\t\tconversationId,\n\t\t\t\t\tuserId: entry.actorType === \"user\" ? entry.actorId : null,\n\t\t\t\t\tvisitorId: entry.actorType === \"visitor\" ? entry.actorId : null,\n\t\t\t\t\taiAgentId: entry.actorType === \"ai_agent\" ? entry.actorId : null,\n\t\t\t\t\tlastSeenAt: entry.lastSeenAt,\n\t\t\t\t\tcreatedAt: entry.lastSeenAt,\n\t\t\t\t\tupdatedAt: entry.lastSeenAt,\n\t\t\t\t\tdeletedAt: null,\n\t\t\t\t}) satisfies ConversationSeen\n\t\t);\n\t}, [conversationId, conversationSeen]);\n}\n\n/**\n * Debounced version of useConversationSeen that delays updates by 500ms\n * to prevent animation conflicts when messages are sent and immediately seen.\n *\n * Use this in UI components where smooth animations are critical.\n */\nexport function useDebouncedConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {},\n\tdelay = 500\n): ConversationSeen[] {\n\tconst seenData = useConversationSeen(conversationId, options);\n\tconst [debouncedSeenData, setDebouncedSeenData] =\n\t\tuseState<ConversationSeen[]>(seenData);\n\tconst timeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n\tuseEffect(() => {\n\t\t// Clear any pending timeout\n\t\tif (timeoutRef.current) {\n\t\t\tclearTimeout(timeoutRef.current);\n\t\t}\n\n\t\t// Set new timeout to update after delay\n\t\ttimeoutRef.current = setTimeout(() => {\n\t\t\tsetDebouncedSeenData(seenData);\n\t\t}, delay);\n\n\t\t// Cleanup on unmount or when seenData changes\n\t\treturn () => {\n\t\t\tif (timeoutRef.current) {\n\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, [seenData, delay]);\n\n\treturn debouncedSeenData;\n}\n"],"mappings":";;;;AAQA,SAAS,YACR,gBACA,WACA,SACC;AACD,QAAO,GAAG,eAAe,GAAG,UAAU,GAAG;;;;;;AAO1C,SAAgB,oBACf,gBACA,UAAsC,EAAE,EACnB;CACrB,MAAM,EAAE,gBAAgB;CACxB,MAAM,iBAAiB,OAAsB,KAAK;AAElD,iBAAgB;AAEf,MAAI,CAAC,gBAAgB;AACpB,kBAAe,UAAU;AACzB;;AAID,MAAI,CAAC,eAAe,YAAY,WAAW,EAC1C;EAID,MAAM,eAAe;AAErB,MAAI,eAAe,YAAY,aAC9B;AAGD,0BAAwB,gBAAgB,YAAY;AACpD,iBAAe,UAAU;IACvB,CAAC,eAAe,CAAC;CAEpB,MAAM,mBAAmB,cAAc,UACtC,iBAAkB,MAAM,cAAc,mBAAmB,OAAQ,KACjE;AAED,QAAO,cAAc;AACpB,MAAI,EAAE,kBAAkB,kBACvB,QAAO,EAAE;AAGV,SAAO,OAAO,OAAO,iBAAiB,CAAC,KACrC,WACC;GACA,IAAI,YAAY,gBAAgB,MAAM,WAAW,MAAM,QAAQ;GAC/D;GACA,QAAQ,MAAM,cAAc,SAAS,MAAM,UAAU;GACrD,WAAW,MAAM,cAAc,YAAY,MAAM,UAAU;GAC3D,WAAW,MAAM,cAAc,aAAa,MAAM,UAAU;GAC5D,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW;GACX,EACF;IACC,CAAC,gBAAgB,iBAAiB,CAAC;;;;;;;;AASvC,SAAgB,6BACf,gBACA,UAAsC,EAAE,EACxC,QAAQ,KACa;CACrB,MAAM,WAAW,oBAAoB,gBAAgB,QAAQ;CAC7D,MAAM,CAAC,mBAAmB,wBACzB,SAA6B,SAAS;CACvC,MAAM,aAAa,OAA8B,KAAK;AAEtD,iBAAgB;AAEf,MAAI,WAAW,QACd,cAAa,WAAW,QAAQ;AAIjC,aAAW,UAAU,iBAAiB;AACrC,wBAAqB,SAAS;KAC5B,MAAM;AAGT,eAAa;AACZ,OAAI,WAAW,QACd,cAAa,WAAW,QAAQ;;IAGhC,CAAC,UAAU,MAAM,CAAC;AAErB,QAAO"}
@@ -0,0 +1,23 @@
1
+ //#region src/hooks/use-new-message-sound.d.ts
2
+ /**
3
+ * Hook to play a sound when a new message arrives.
4
+ *
5
+ * @param options - Optional configuration for volume and playback speed
6
+ * @returns Function to play the new message sound
7
+ *
8
+ * @example
9
+ * const playNewMessageSound = useNewMessageSound({ volume: 0.8, playbackRate: 1.1 });
10
+ *
11
+ * useEffect(() => {
12
+ * if (hasNewMessage) {
13
+ * playNewMessageSound();
14
+ * }
15
+ * }, [hasNewMessage]);
16
+ */
17
+ declare function useNewMessageSound(options?: {
18
+ volume?: number;
19
+ playbackRate?: number;
20
+ }): () => void;
21
+ //#endregion
22
+ export { useNewMessageSound };
23
+ //# sourceMappingURL=use-new-message-sound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-new-message-sound.d.ts","names":[],"sources":["../../src/hooks/use-new-message-sound.ts"],"sourcesContent":[],"mappings":";;AAqBA;;;;;;;;;;;;;;iBAAgB,kBAAA"}
@@ -0,0 +1,34 @@
1
+ import { useSoundEffect } from "./use-sound-effect.js";
2
+ import { useCallback } from "react";
3
+
4
+ //#region src/hooks/use-new-message-sound.ts
5
+ const NEW_MESSAGE_SOUND_PATH = "/sounds/new-message.wav";
6
+ /**
7
+ * Hook to play a sound when a new message arrives.
8
+ *
9
+ * @param options - Optional configuration for volume and playback speed
10
+ * @returns Function to play the new message sound
11
+ *
12
+ * @example
13
+ * const playNewMessageSound = useNewMessageSound({ volume: 0.8, playbackRate: 1.1 });
14
+ *
15
+ * useEffect(() => {
16
+ * if (hasNewMessage) {
17
+ * playNewMessageSound();
18
+ * }
19
+ * }, [hasNewMessage]);
20
+ */
21
+ function useNewMessageSound(options) {
22
+ const { play } = useSoundEffect(NEW_MESSAGE_SOUND_PATH, {
23
+ loop: false,
24
+ volume: options?.volume ?? .7,
25
+ playbackRate: options?.playbackRate ?? 1
26
+ });
27
+ return useCallback(() => {
28
+ play();
29
+ }, [play]);
30
+ }
31
+
32
+ //#endregion
33
+ export { useNewMessageSound };
34
+ //# sourceMappingURL=use-new-message-sound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-new-message-sound.js","names":[],"sources":["../../src/hooks/use-new-message-sound.ts"],"sourcesContent":["import { useCallback } from \"react\";\nimport { useSoundEffect } from \"./use-sound-effect\";\n\n// Use a path that can be served from public directory\nconst NEW_MESSAGE_SOUND_PATH = \"/sounds/new-message.wav\";\n\n/**\n * Hook to play a sound when a new message arrives.\n *\n * @param options - Optional configuration for volume and playback speed\n * @returns Function to play the new message sound\n *\n * @example\n * const playNewMessageSound = useNewMessageSound({ volume: 0.8, playbackRate: 1.1 });\n *\n * useEffect(() => {\n * if (hasNewMessage) {\n * playNewMessageSound();\n * }\n * }, [hasNewMessage]);\n */\nexport function useNewMessageSound(options?: {\n\tvolume?: number;\n\tplaybackRate?: number;\n}): () => void {\n\tconst { play } = useSoundEffect(NEW_MESSAGE_SOUND_PATH, {\n\t\tloop: false,\n\t\tvolume: options?.volume ?? 0.7,\n\t\tplaybackRate: options?.playbackRate ?? 1.0,\n\t});\n\n\treturn useCallback(() => {\n\t\tplay();\n\t}, [play]);\n}\n"],"mappings":";;;;AAIA,MAAM,yBAAyB;;;;;;;;;;;;;;;;AAiB/B,SAAgB,mBAAmB,SAGpB;CACd,MAAM,EAAE,SAAS,eAAe,wBAAwB;EACvD,MAAM;EACN,QAAQ,SAAS,UAAU;EAC3B,cAAc,SAAS,gBAAgB;EACvC,CAAC;AAEF,QAAO,kBAAkB;AACxB,QAAM;IACJ,CAAC,KAAK,CAAC"}
@@ -9,7 +9,7 @@ function toError(error) {
9
9
  return /* @__PURE__ */ new Error("Unknown error");
10
10
  }
11
11
  function buildTimelineItemPayload(body, conversationId, visitorId, messageId) {
12
- const nowIso = (/* @__PURE__ */ new Date()).toISOString();
12
+ const nowIso = typeof window !== "undefined" ? (/* @__PURE__ */ new Date()).toISOString() : "";
13
13
  return {
14
14
  id: messageId ?? generateMessageId(),
15
15
  conversationId,
@@ -1 +1 @@
1
- {"version":3,"file":"use-send-message.js","names":["initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined","result: SendMessageResult"],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { generateMessageId } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useCallback, useState } from \"react\";\n\nimport { useSupport } from \"../provider\";\n\nexport type SendMessageOptions = {\n\tconversationId?: string | null;\n\tmessage: string;\n\tfiles?: File[];\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\t/**\n\t * Optional message ID to use for the optimistic update and API request.\n\t * When not provided, a ULID will be generated on the client.\n\t */\n\tmessageId?: string;\n\tonSuccess?: (conversationId: string, messageId: string) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type SendMessageResult = {\n\tconversationId: string;\n\tmessageId: string;\n\tconversation?: CreateConversationResponseBody[\"conversation\"];\n\tinitialTimelineItems?: CreateConversationResponseBody[\"initialTimelineItems\"];\n};\n\nexport type UseSendMessageResult = {\n\tmutate: (options: SendMessageOptions) => void;\n\tmutateAsync: (\n\t\toptions: SendMessageOptions\n\t) => Promise<SendMessageResult | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nexport type UseSendMessageOptions = {\n\tclient?: CossistantClient;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\nfunction buildTimelineItemPayload(\n\tbody: string,\n\tconversationId: string,\n\tvisitorId: string | null,\n\tmessageId?: string\n): TimelineItem {\n\tconst nowIso = new Date().toISOString();\n\tconst id = messageId ?? generateMessageId();\n\n\treturn {\n\t\tid,\n\t\tconversationId,\n\t\torganizationId: \"\", // Will be set by backend\n\t\ttype: \"message\" as const,\n\t\ttext: body,\n\t\tparts: [{ type: \"text\" as const, text: body }],\n\t\tvisibility: \"public\" as const,\n\t\tuserId: null,\n\t\taiAgentId: null,\n\t\tvisitorId: visitorId ?? null,\n\t\tcreatedAt: nowIso,\n\t\tdeletedAt: null,\n\t} satisfies TimelineItem;\n}\n\n/**\n * Sends visitor messages while handling optimistic pending conversations and\n * exposing react-query-like mutation state.\n */\nexport function useSendMessage(\n\toptions: UseSendMessageOptions = {}\n): UseSendMessageResult {\n\tconst { client: contextClient } = useSupport();\n\tconst client = options.client ?? contextClient;\n\n\tconst [isPending, setIsPending] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst mutateAsync = useCallback(\n\t\tasync (payload: SendMessageOptions): Promise<SendMessageResult | null> => {\n\t\t\tconst {\n\t\t\t\tconversationId: providedConversationId,\n\t\t\t\tmessage,\n\t\t\t\tdefaultTimelineItems = [],\n\t\t\t\tvisitorId,\n\t\t\t\tmessageId: providedMessageId,\n\t\t\t\tonSuccess,\n\t\t\t\tonError,\n\t\t\t} = payload;\n\n\t\t\tif (!message.trim()) {\n\t\t\t\tconst emptyMessageError = new Error(\"Message cannot be empty\");\n\t\t\t\tsetError(emptyMessageError);\n\t\t\t\tonError?.(emptyMessageError);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\tlet conversationId = providedConversationId ?? undefined;\n\t\t\t\tlet preparedDefaultTimelineItems = defaultTimelineItems;\n\t\t\t\tlet initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined;\n\n\t\t\t\tif (!conversationId) {\n\t\t\t\t\tconst initiated = client.initiateConversation({\n\t\t\t\t\t\tdefaultTimelineItems,\n\t\t\t\t\t\tvisitorId: visitorId ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tconversationId = initiated.conversationId;\n\t\t\t\t\tpreparedDefaultTimelineItems = initiated.defaultTimelineItems;\n\t\t\t\t\tinitialConversation = initiated.conversation;\n\t\t\t\t}\n\n\t\t\t\tconst timelineItemPayload = buildTimelineItemPayload(\n\t\t\t\t\tmessage,\n\t\t\t\t\tconversationId,\n\t\t\t\t\tvisitorId ?? null,\n\t\t\t\t\tprovidedMessageId\n\t\t\t\t);\n\n\t\t\t\tconst response = await client.sendMessage({\n\t\t\t\t\tconversationId,\n\t\t\t\t\titem: {\n\t\t\t\t\t\tid: timelineItemPayload.id,\n\t\t\t\t\t\ttext: timelineItemPayload.text ?? \"\",\n\t\t\t\t\t\ttype:\n\t\t\t\t\t\t\ttimelineItemPayload.type === \"identification\"\n\t\t\t\t\t\t\t\t? \"message\"\n\t\t\t\t\t\t\t\t: timelineItemPayload.type,\n\t\t\t\t\t\tvisibility: timelineItemPayload.visibility,\n\t\t\t\t\t\tuserId: timelineItemPayload.userId,\n\t\t\t\t\t\taiAgentId: timelineItemPayload.aiAgentId,\n\t\t\t\t\t\tvisitorId: timelineItemPayload.visitorId,\n\t\t\t\t\t\tcreatedAt: timelineItemPayload.createdAt,\n\t\t\t\t\t\tparts: timelineItemPayload.parts,\n\t\t\t\t\t},\n\t\t\t\t\tcreateIfPending: true,\n\t\t\t\t});\n\n\t\t\t\tconst messageId = response.item.id;\n\n\t\t\t\tif (!messageId) {\n\t\t\t\t\tthrow new Error(\"SendMessage response missing item.id\");\n\t\t\t\t}\n\n\t\t\t\tconst result: SendMessageResult = {\n\t\t\t\t\tconversationId,\n\t\t\t\t\tmessageId,\n\t\t\t\t};\n\n\t\t\t\tif (\"conversation\" in response && response.conversation) {\n\t\t\t\t\tresult.conversation = response.conversation;\n\t\t\t\t\tresult.initialTimelineItems = response.initialTimelineItems;\n\t\t\t\t} else if (initialConversation) {\n\t\t\t\t\tresult.conversation = initialConversation;\n\t\t\t\t\tresult.initialTimelineItems = preparedDefaultTimelineItems;\n\t\t\t\t}\n\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(null);\n\t\t\t\tonSuccess?.(result.conversationId, result.messageId);\n\t\t\t\treturn result;\n\t\t\t} catch (raw) {\n\t\t\t\tconst normalised = toError(raw);\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(normalised);\n\t\t\t\tonError?.(normalised);\n\t\t\t\tthrow normalised;\n\t\t\t}\n\t\t},\n\t\t[client]\n\t);\n\n\tconst mutate = useCallback(\n\t\t(opts: SendMessageOptions) => {\n\t\t\tvoid mutateAsync(opts).catch(() => {\n\t\t\t\t// Swallow errors to mimic react-query behaviour for mutate\n\t\t\t});\n\t\t},\n\t\t[mutateAsync]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisPending,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":";;;;;AA4CA,SAAS,QAAQ,OAAuB;AACvC,KAAI,iBAAiB,MACpB,QAAO;AAGR,KAAI,OAAO,UAAU,SACpB,QAAO,IAAI,MAAM,MAAM;AAGxB,wBAAO,IAAI,MAAM,gBAAgB;;AAGlC,SAAS,yBACR,MACA,gBACA,WACA,WACe;CACf,MAAM,0BAAS,IAAI,MAAM,EAAC,aAAa;AAGvC,QAAO;EACN,IAHU,aAAa,mBAAmB;EAI1C;EACA,gBAAgB;EAChB,MAAM;EACN,MAAM;EACN,OAAO,CAAC;GAAE,MAAM;GAAiB,MAAM;GAAM,CAAC;EAC9C,YAAY;EACZ,QAAQ;EACR,WAAW;EACX,WAAW,aAAa;EACxB,WAAW;EACX,WAAW;EACX;;;;;;AAOF,SAAgB,eACf,UAAiC,EAAE,EACZ;CACvB,MAAM,EAAE,QAAQ,kBAAkB,YAAY;CAC9C,MAAM,SAAS,QAAQ,UAAU;CAEjC,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,cAAc,YACnB,OAAO,YAAmE;EACzE,MAAM,EACL,gBAAgB,wBAChB,SACA,uBAAuB,EAAE,EACzB,WACA,WAAW,mBACX,WACA,YACG;AAEJ,MAAI,CAAC,QAAQ,MAAM,EAAE;GACpB,MAAM,oCAAoB,IAAI,MAAM,0BAA0B;AAC9D,YAAS,kBAAkB;AAC3B,aAAU,kBAAkB;AAC5B,UAAO;;AAGR,eAAa,KAAK;AAClB,WAAS,KAAK;AAEd,MAAI;GACH,IAAI,iBAAiB,0BAA0B;GAC/C,IAAI,+BAA+B;GACnC,IAAIA;AAIJ,OAAI,CAAC,gBAAgB;IACpB,MAAM,YAAY,OAAO,qBAAqB;KAC7C;KACA,WAAW,aAAa;KACxB,CAAC;AACF,qBAAiB,UAAU;AAC3B,mCAA+B,UAAU;AACzC,0BAAsB,UAAU;;GAGjC,MAAM,sBAAsB,yBAC3B,SACA,gBACA,aAAa,MACb,kBACA;GAED,MAAM,WAAW,MAAM,OAAO,YAAY;IACzC;IACA,MAAM;KACL,IAAI,oBAAoB;KACxB,MAAM,oBAAoB,QAAQ;KAClC,MACC,oBAAoB,SAAS,mBAC1B,YACA,oBAAoB;KACxB,YAAY,oBAAoB;KAChC,QAAQ,oBAAoB;KAC5B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,OAAO,oBAAoB;KAC3B;IACD,iBAAiB;IACjB,CAAC;GAEF,MAAM,YAAY,SAAS,KAAK;AAEhC,OAAI,CAAC,UACJ,OAAM,IAAI,MAAM,uCAAuC;GAGxD,MAAMC,SAA4B;IACjC;IACA;IACA;AAED,OAAI,kBAAkB,YAAY,SAAS,cAAc;AACxD,WAAO,eAAe,SAAS;AAC/B,WAAO,uBAAuB,SAAS;cAC7B,qBAAqB;AAC/B,WAAO,eAAe;AACtB,WAAO,uBAAuB;;AAG/B,gBAAa,MAAM;AACnB,YAAS,KAAK;AACd,eAAY,OAAO,gBAAgB,OAAO,UAAU;AACpD,UAAO;WACC,KAAK;GACb,MAAM,aAAa,QAAQ,IAAI;AAC/B,gBAAa,MAAM;AACnB,YAAS,WAAW;AACpB,aAAU,WAAW;AACrB,SAAM;;IAGR,CAAC,OAAO,CACR;AAgBD,QAAO;EACN,QAfc,aACb,SAA6B;AAC7B,GAAK,YAAY,KAAK,CAAC,YAAY,GAEjC;KAEH,CAAC,YAAY,CACb;EASA;EACA;EACA;EACA,OAVa,kBAAkB;AAC/B,YAAS,KAAK;AACd,gBAAa,MAAM;KACjB,EAAE,CAAC;EAQL"}
1
+ {"version":3,"file":"use-send-message.js","names":["initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined","result: SendMessageResult"],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { generateMessageId } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useCallback, useState } from \"react\";\n\nimport { useSupport } from \"../provider\";\n\nexport type SendMessageOptions = {\n\tconversationId?: string | null;\n\tmessage: string;\n\tfiles?: File[];\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\t/**\n\t * Optional message ID to use for the optimistic update and API request.\n\t * When not provided, a ULID will be generated on the client.\n\t */\n\tmessageId?: string;\n\tonSuccess?: (conversationId: string, messageId: string) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type SendMessageResult = {\n\tconversationId: string;\n\tmessageId: string;\n\tconversation?: CreateConversationResponseBody[\"conversation\"];\n\tinitialTimelineItems?: CreateConversationResponseBody[\"initialTimelineItems\"];\n};\n\nexport type UseSendMessageResult = {\n\tmutate: (options: SendMessageOptions) => void;\n\tmutateAsync: (\n\t\toptions: SendMessageOptions\n\t) => Promise<SendMessageResult | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nexport type UseSendMessageOptions = {\n\tclient?: CossistantClient;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\nfunction buildTimelineItemPayload(\n\tbody: string,\n\tconversationId: string,\n\tvisitorId: string | null,\n\tmessageId?: string\n): TimelineItem {\n\tconst nowIso = typeof window !== \"undefined\" ? new Date().toISOString() : \"\";\n\tconst id = messageId ?? generateMessageId();\n\n\treturn {\n\t\tid,\n\t\tconversationId,\n\t\torganizationId: \"\", // Will be set by backend\n\t\ttype: \"message\" as const,\n\t\ttext: body,\n\t\tparts: [{ type: \"text\" as const, text: body }],\n\t\tvisibility: \"public\" as const,\n\t\tuserId: null,\n\t\taiAgentId: null,\n\t\tvisitorId: visitorId ?? null,\n\t\tcreatedAt: nowIso,\n\t\tdeletedAt: null,\n\t} satisfies TimelineItem;\n}\n\n/**\n * Sends visitor messages while handling optimistic pending conversations and\n * exposing react-query-like mutation state.\n */\nexport function useSendMessage(\n\toptions: UseSendMessageOptions = {}\n): UseSendMessageResult {\n\tconst { client: contextClient } = useSupport();\n\tconst client = options.client ?? contextClient;\n\n\tconst [isPending, setIsPending] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst mutateAsync = useCallback(\n\t\tasync (payload: SendMessageOptions): Promise<SendMessageResult | null> => {\n\t\t\tconst {\n\t\t\t\tconversationId: providedConversationId,\n\t\t\t\tmessage,\n\t\t\t\tdefaultTimelineItems = [],\n\t\t\t\tvisitorId,\n\t\t\t\tmessageId: providedMessageId,\n\t\t\t\tonSuccess,\n\t\t\t\tonError,\n\t\t\t} = payload;\n\n\t\t\tif (!message.trim()) {\n\t\t\t\tconst emptyMessageError = new Error(\"Message cannot be empty\");\n\t\t\t\tsetError(emptyMessageError);\n\t\t\t\tonError?.(emptyMessageError);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\tlet conversationId = providedConversationId ?? undefined;\n\t\t\t\tlet preparedDefaultTimelineItems = defaultTimelineItems;\n\t\t\t\tlet initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined;\n\n\t\t\t\tif (!conversationId) {\n\t\t\t\t\tconst initiated = client.initiateConversation({\n\t\t\t\t\t\tdefaultTimelineItems,\n\t\t\t\t\t\tvisitorId: visitorId ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tconversationId = initiated.conversationId;\n\t\t\t\t\tpreparedDefaultTimelineItems = initiated.defaultTimelineItems;\n\t\t\t\t\tinitialConversation = initiated.conversation;\n\t\t\t\t}\n\n\t\t\t\tconst timelineItemPayload = buildTimelineItemPayload(\n\t\t\t\t\tmessage,\n\t\t\t\t\tconversationId,\n\t\t\t\t\tvisitorId ?? null,\n\t\t\t\t\tprovidedMessageId\n\t\t\t\t);\n\n\t\t\t\tconst response = await client.sendMessage({\n\t\t\t\t\tconversationId,\n\t\t\t\t\titem: {\n\t\t\t\t\t\tid: timelineItemPayload.id,\n\t\t\t\t\t\ttext: timelineItemPayload.text ?? \"\",\n\t\t\t\t\t\ttype:\n\t\t\t\t\t\t\ttimelineItemPayload.type === \"identification\"\n\t\t\t\t\t\t\t\t? \"message\"\n\t\t\t\t\t\t\t\t: timelineItemPayload.type,\n\t\t\t\t\t\tvisibility: timelineItemPayload.visibility,\n\t\t\t\t\t\tuserId: timelineItemPayload.userId,\n\t\t\t\t\t\taiAgentId: timelineItemPayload.aiAgentId,\n\t\t\t\t\t\tvisitorId: timelineItemPayload.visitorId,\n\t\t\t\t\t\tcreatedAt: timelineItemPayload.createdAt,\n\t\t\t\t\t\tparts: timelineItemPayload.parts,\n\t\t\t\t\t},\n\t\t\t\t\tcreateIfPending: true,\n\t\t\t\t});\n\n\t\t\t\tconst messageId = response.item.id;\n\n\t\t\t\tif (!messageId) {\n\t\t\t\t\tthrow new Error(\"SendMessage response missing item.id\");\n\t\t\t\t}\n\n\t\t\t\tconst result: SendMessageResult = {\n\t\t\t\t\tconversationId,\n\t\t\t\t\tmessageId,\n\t\t\t\t};\n\n\t\t\t\tif (\"conversation\" in response && response.conversation) {\n\t\t\t\t\tresult.conversation = response.conversation;\n\t\t\t\t\tresult.initialTimelineItems = response.initialTimelineItems;\n\t\t\t\t} else if (initialConversation) {\n\t\t\t\t\tresult.conversation = initialConversation;\n\t\t\t\t\tresult.initialTimelineItems = preparedDefaultTimelineItems;\n\t\t\t\t}\n\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(null);\n\t\t\t\tonSuccess?.(result.conversationId, result.messageId);\n\t\t\t\treturn result;\n\t\t\t} catch (raw) {\n\t\t\t\tconst normalised = toError(raw);\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(normalised);\n\t\t\t\tonError?.(normalised);\n\t\t\t\tthrow normalised;\n\t\t\t}\n\t\t},\n\t\t[client]\n\t);\n\n\tconst mutate = useCallback(\n\t\t(opts: SendMessageOptions) => {\n\t\t\tvoid mutateAsync(opts).catch(() => {\n\t\t\t\t// Swallow errors to mimic react-query behaviour for mutate\n\t\t\t});\n\t\t},\n\t\t[mutateAsync]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisPending,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":";;;;;AA4CA,SAAS,QAAQ,OAAuB;AACvC,KAAI,iBAAiB,MACpB,QAAO;AAGR,KAAI,OAAO,UAAU,SACpB,QAAO,IAAI,MAAM,MAAM;AAGxB,wBAAO,IAAI,MAAM,gBAAgB;;AAGlC,SAAS,yBACR,MACA,gBACA,WACA,WACe;CACf,MAAM,SAAS,OAAO,WAAW,+BAAc,IAAI,MAAM,EAAC,aAAa,GAAG;AAG1E,QAAO;EACN,IAHU,aAAa,mBAAmB;EAI1C;EACA,gBAAgB;EAChB,MAAM;EACN,MAAM;EACN,OAAO,CAAC;GAAE,MAAM;GAAiB,MAAM;GAAM,CAAC;EAC9C,YAAY;EACZ,QAAQ;EACR,WAAW;EACX,WAAW,aAAa;EACxB,WAAW;EACX,WAAW;EACX;;;;;;AAOF,SAAgB,eACf,UAAiC,EAAE,EACZ;CACvB,MAAM,EAAE,QAAQ,kBAAkB,YAAY;CAC9C,MAAM,SAAS,QAAQ,UAAU;CAEjC,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,cAAc,YACnB,OAAO,YAAmE;EACzE,MAAM,EACL,gBAAgB,wBAChB,SACA,uBAAuB,EAAE,EACzB,WACA,WAAW,mBACX,WACA,YACG;AAEJ,MAAI,CAAC,QAAQ,MAAM,EAAE;GACpB,MAAM,oCAAoB,IAAI,MAAM,0BAA0B;AAC9D,YAAS,kBAAkB;AAC3B,aAAU,kBAAkB;AAC5B,UAAO;;AAGR,eAAa,KAAK;AAClB,WAAS,KAAK;AAEd,MAAI;GACH,IAAI,iBAAiB,0BAA0B;GAC/C,IAAI,+BAA+B;GACnC,IAAIA;AAIJ,OAAI,CAAC,gBAAgB;IACpB,MAAM,YAAY,OAAO,qBAAqB;KAC7C;KACA,WAAW,aAAa;KACxB,CAAC;AACF,qBAAiB,UAAU;AAC3B,mCAA+B,UAAU;AACzC,0BAAsB,UAAU;;GAGjC,MAAM,sBAAsB,yBAC3B,SACA,gBACA,aAAa,MACb,kBACA;GAED,MAAM,WAAW,MAAM,OAAO,YAAY;IACzC;IACA,MAAM;KACL,IAAI,oBAAoB;KACxB,MAAM,oBAAoB,QAAQ;KAClC,MACC,oBAAoB,SAAS,mBAC1B,YACA,oBAAoB;KACxB,YAAY,oBAAoB;KAChC,QAAQ,oBAAoB;KAC5B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,OAAO,oBAAoB;KAC3B;IACD,iBAAiB;IACjB,CAAC;GAEF,MAAM,YAAY,SAAS,KAAK;AAEhC,OAAI,CAAC,UACJ,OAAM,IAAI,MAAM,uCAAuC;GAGxD,MAAMC,SAA4B;IACjC;IACA;IACA;AAED,OAAI,kBAAkB,YAAY,SAAS,cAAc;AACxD,WAAO,eAAe,SAAS;AAC/B,WAAO,uBAAuB,SAAS;cAC7B,qBAAqB;AAC/B,WAAO,eAAe;AACtB,WAAO,uBAAuB;;AAG/B,gBAAa,MAAM;AACnB,YAAS,KAAK;AACd,eAAY,OAAO,gBAAgB,OAAO,UAAU;AACpD,UAAO;WACC,KAAK;GACb,MAAM,aAAa,QAAQ,IAAI;AAC/B,gBAAa,MAAM;AACnB,YAAS,WAAW;AACpB,aAAU,WAAW;AACrB,SAAM;;IAGR,CAAC,OAAO,CACR;AAgBD,QAAO;EACN,QAfc,aACb,SAA6B;AAC7B,GAAK,YAAY,KAAK,CAAC,YAAY,GAEjC;KAEH,CAAC,YAAY,CACb;EASA;EACA;EACA;EACA,OAVa,kBAAkB;AAC/B,YAAS,KAAK;AACd,gBAAa,MAAM;KACjB,EAAE,CAAC;EAQL"}
@@ -0,0 +1,30 @@
1
+ //#region src/hooks/use-sound-effect.d.ts
2
+ type UseSoundEffectOptions = {
3
+ loop?: boolean;
4
+ volume?: number;
5
+ playbackRate?: number;
6
+ };
7
+ type UseSoundEffectReturn = {
8
+ play: () => void;
9
+ stop: () => void;
10
+ isPlaying: boolean;
11
+ isLoading: boolean;
12
+ error: Error | null;
13
+ };
14
+ /**
15
+ * Hook to play sound effects using the Web Audio API.
16
+ *
17
+ * @param soundPath - Path to the sound file (relative to public directory or absolute URL)
18
+ * @param options - Configuration options for the sound
19
+ * @returns Object with play, stop functions and state
20
+ *
21
+ * @example
22
+ * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {
23
+ * loop: false,
24
+ * volume: 0.5
25
+ * });
26
+ */
27
+ declare function useSoundEffect(soundPath: string, options?: UseSoundEffectOptions): UseSoundEffectReturn;
28
+ //#endregion
29
+ export { UseSoundEffectOptions, UseSoundEffectReturn, useSoundEffect };
30
+ //# sourceMappingURL=use-sound-effect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sound-effect.d.ts","names":[],"sources":["../../src/hooks/use-sound-effect.ts"],"sourcesContent":[],"mappings":";KAEY,qBAAA;EAAA,IAAA,CAAA,EAAA,OAAA;EAMA,MAAA,CAAA,EAAA,MAAA;EAqBI,YAAA,CAAA,EAAA,MAAc;;KArBlB,oBAAA;;;;;SAKJ;;;;;;;;;;;;;;;iBAgBQ,cAAA,8BAEN,wBACP"}
@@ -0,0 +1,104 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ //#region src/hooks/use-sound-effect.ts
4
+ /**
5
+ * Hook to play sound effects using the Web Audio API.
6
+ *
7
+ * @param soundPath - Path to the sound file (relative to public directory or absolute URL)
8
+ * @param options - Configuration options for the sound
9
+ * @returns Object with play, stop functions and state
10
+ *
11
+ * @example
12
+ * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {
13
+ * loop: false,
14
+ * volume: 0.5
15
+ * });
16
+ */
17
+ function useSoundEffect(soundPath, options = {}) {
18
+ const { loop = false, volume = 1, playbackRate = 1 } = options;
19
+ const [isPlaying, setIsPlaying] = useState(false);
20
+ const [isLoading, setIsLoading] = useState(true);
21
+ const [error, setError] = useState(null);
22
+ const audioContextRef = useRef(null);
23
+ const audioBufferRef = useRef(null);
24
+ const sourceNodeRef = useRef(null);
25
+ const gainNodeRef = useRef(null);
26
+ useEffect(() => {
27
+ let mounted = true;
28
+ const initAudio = async () => {
29
+ try {
30
+ if (!audioContextRef.current) audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
31
+ const response = await fetch(soundPath);
32
+ if (!response.ok) throw new Error(`Failed to load sound: ${response.statusText}`);
33
+ const arrayBuffer = await response.arrayBuffer();
34
+ const audioBuffer = await audioContextRef.current.decodeAudioData(arrayBuffer);
35
+ if (mounted) {
36
+ audioBufferRef.current = audioBuffer;
37
+ setIsLoading(false);
38
+ }
39
+ } catch (err) {
40
+ if (mounted) {
41
+ setError(err instanceof Error ? err : /* @__PURE__ */ new Error("Failed to load sound"));
42
+ setIsLoading(false);
43
+ }
44
+ }
45
+ };
46
+ initAudio();
47
+ return () => {
48
+ mounted = false;
49
+ };
50
+ }, [soundPath]);
51
+ const play = useCallback(() => {
52
+ const audioContext = audioContextRef.current;
53
+ const audioBuffer = audioBufferRef.current;
54
+ if (!(audioContext && audioBuffer && !isLoading && !error)) return;
55
+ if (sourceNodeRef.current) try {
56
+ sourceNodeRef.current.stop();
57
+ } catch {}
58
+ const source = audioContext.createBufferSource();
59
+ source.buffer = audioBuffer;
60
+ source.loop = loop;
61
+ source.playbackRate.value = playbackRate;
62
+ const gainNode = audioContext.createGain();
63
+ gainNode.gain.value = volume;
64
+ source.connect(gainNode);
65
+ gainNode.connect(audioContext.destination);
66
+ sourceNodeRef.current = source;
67
+ gainNodeRef.current = gainNode;
68
+ source.onended = () => {
69
+ if (!loop) setIsPlaying(false);
70
+ };
71
+ source.start(0);
72
+ setIsPlaying(true);
73
+ }, [
74
+ loop,
75
+ volume,
76
+ playbackRate,
77
+ isLoading,
78
+ error
79
+ ]);
80
+ const stop = useCallback(() => {
81
+ if (sourceNodeRef.current) {
82
+ try {
83
+ sourceNodeRef.current.stop();
84
+ sourceNodeRef.current.disconnect();
85
+ } catch {}
86
+ sourceNodeRef.current = null;
87
+ }
88
+ setIsPlaying(false);
89
+ }, []);
90
+ useEffect(() => () => {
91
+ stop();
92
+ }, [stop]);
93
+ return {
94
+ play,
95
+ stop,
96
+ isPlaying,
97
+ isLoading,
98
+ error
99
+ };
100
+ }
101
+
102
+ //#endregion
103
+ export { useSoundEffect };
104
+ //# sourceMappingURL=use-sound-effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-sound-effect.js","names":[],"sources":["../../src/hooks/use-sound-effect.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type UseSoundEffectOptions = {\n\tloop?: boolean;\n\tvolume?: number;\n\tplaybackRate?: number;\n};\n\nexport type UseSoundEffectReturn = {\n\tplay: () => void;\n\tstop: () => void;\n\tisPlaying: boolean;\n\tisLoading: boolean;\n\terror: Error | null;\n};\n\n/**\n * Hook to play sound effects using the Web Audio API.\n *\n * @param soundPath - Path to the sound file (relative to public directory or absolute URL)\n * @param options - Configuration options for the sound\n * @returns Object with play, stop functions and state\n *\n * @example\n * const { play, stop, isPlaying } = useSoundEffect('/sounds/notification.wav', {\n * loop: false,\n * volume: 0.5\n * });\n */\nexport function useSoundEffect(\n\tsoundPath: string,\n\toptions: UseSoundEffectOptions = {}\n): UseSoundEffectReturn {\n\tconst { loop = false, volume = 1.0, playbackRate = 1.0 } = options;\n\n\tconst [isPlaying, setIsPlaying] = useState(false);\n\tconst [isLoading, setIsLoading] = useState(true);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst audioContextRef = useRef<AudioContext | null>(null);\n\tconst audioBufferRef = useRef<AudioBuffer | null>(null);\n\tconst sourceNodeRef = useRef<AudioBufferSourceNode | null>(null);\n\tconst gainNodeRef = useRef<GainNode | null>(null);\n\n\t// Initialize audio context and load sound\n\tuseEffect(() => {\n\t\tlet mounted = true;\n\n\t\tconst initAudio = async () => {\n\t\t\ttry {\n\t\t\t\t// Create audio context if it doesn't exist\n\t\t\t\tif (!audioContextRef.current) {\n\t\t\t\t\taudioContextRef.current = new (\n\t\t\t\t\t\twindow.AudioContext ||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\twindow as typeof window & {\n\t\t\t\t\t\t\t\twebkitAudioContext?: typeof AudioContext;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t).webkitAudioContext\n\t\t\t\t\t)();\n\t\t\t\t}\n\n\t\t\t\t// Load the audio file\n\t\t\t\tconst response = await fetch(soundPath);\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`Failed to load sound: ${response.statusText}`);\n\t\t\t\t}\n\n\t\t\t\tconst arrayBuffer = await response.arrayBuffer();\n\t\t\t\tconst audioBuffer =\n\t\t\t\t\tawait audioContextRef.current.decodeAudioData(arrayBuffer);\n\n\t\t\t\tif (mounted) {\n\t\t\t\t\taudioBufferRef.current = audioBuffer;\n\t\t\t\t\tsetIsLoading(false);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tif (mounted) {\n\t\t\t\t\tsetError(\n\t\t\t\t\t\terr instanceof Error ? err : new Error(\"Failed to load sound\")\n\t\t\t\t\t);\n\t\t\t\t\tsetIsLoading(false);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tinitAudio();\n\n\t\treturn () => {\n\t\t\tmounted = false;\n\t\t};\n\t}, [soundPath]);\n\n\t// Play sound\n\tconst play = useCallback(() => {\n\t\tconst audioContext = audioContextRef.current;\n\t\tconst audioBuffer = audioBufferRef.current;\n\n\t\tconst canPlay = audioContext && audioBuffer && !isLoading && !error;\n\n\t\tif (!canPlay) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Stop any currently playing sound\n\t\tif (sourceNodeRef.current) {\n\t\t\ttry {\n\t\t\t\tsourceNodeRef.current.stop();\n\t\t\t} catch {\n\t\t\t\t// Ignore errors if already stopped\n\t\t\t}\n\t\t}\n\n\t\t// Create new source node\n\t\tconst source = audioContext.createBufferSource();\n\t\tsource.buffer = audioBuffer;\n\t\tsource.loop = loop;\n\t\tsource.playbackRate.value = playbackRate;\n\n\t\t// Create gain node for volume control\n\t\tconst gainNode = audioContext.createGain();\n\t\tgainNode.gain.value = volume;\n\n\t\t// Connect nodes: source -> gain -> destination\n\t\tsource.connect(gainNode);\n\t\tgainNode.connect(audioContext.destination);\n\n\t\t// Store references\n\t\tsourceNodeRef.current = source;\n\t\tgainNodeRef.current = gainNode;\n\n\t\t// Handle end event\n\t\tsource.onended = () => {\n\t\t\tif (!loop) {\n\t\t\t\tsetIsPlaying(false);\n\t\t\t}\n\t\t};\n\n\t\t// Start playback\n\t\tsource.start(0);\n\t\tsetIsPlaying(true);\n\t}, [loop, volume, playbackRate, isLoading, error]);\n\n\t// Stop sound\n\tconst stop = useCallback(() => {\n\t\tif (sourceNodeRef.current) {\n\t\t\ttry {\n\t\t\t\tsourceNodeRef.current.stop();\n\t\t\t\tsourceNodeRef.current.disconnect();\n\t\t\t} catch {\n\t\t\t\t// Ignore errors if already stopped\n\t\t\t}\n\t\t\tsourceNodeRef.current = null;\n\t\t}\n\t\tsetIsPlaying(false);\n\t}, []);\n\n\t// Cleanup on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tstop();\n\t\t},\n\t\t[stop]\n\t);\n\n\treturn {\n\t\tplay,\n\t\tstop,\n\t\tisPlaying,\n\t\tisLoading,\n\t\terror,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6BA,SAAgB,eACf,WACA,UAAiC,EAAE,EACZ;CACvB,MAAM,EAAE,OAAO,OAAO,SAAS,GAAK,eAAe,MAAQ;CAE3D,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,kBAAkB,OAA4B,KAAK;CACzD,MAAM,iBAAiB,OAA2B,KAAK;CACvD,MAAM,gBAAgB,OAAqC,KAAK;CAChE,MAAM,cAAc,OAAwB,KAAK;AAGjD,iBAAgB;EACf,IAAI,UAAU;EAEd,MAAM,YAAY,YAAY;AAC7B,OAAI;AAEH,QAAI,CAAC,gBAAgB,QACpB,iBAAgB,UAAU,KACzB,OAAO,gBAEN,OAGC,qBACA;IAIJ,MAAM,WAAW,MAAM,MAAM,UAAU;AACvC,QAAI,CAAC,SAAS,GACb,OAAM,IAAI,MAAM,yBAAyB,SAAS,aAAa;IAGhE,MAAM,cAAc,MAAM,SAAS,aAAa;IAChD,MAAM,cACL,MAAM,gBAAgB,QAAQ,gBAAgB,YAAY;AAE3D,QAAI,SAAS;AACZ,oBAAe,UAAU;AACzB,kBAAa,MAAM;;YAEZ,KAAK;AACb,QAAI,SAAS;AACZ,cACC,eAAe,QAAQ,sBAAM,IAAI,MAAM,uBAAuB,CAC9D;AACD,kBAAa,MAAM;;;;AAKtB,aAAW;AAEX,eAAa;AACZ,aAAU;;IAET,CAAC,UAAU,CAAC;CAGf,MAAM,OAAO,kBAAkB;EAC9B,MAAM,eAAe,gBAAgB;EACrC,MAAM,cAAc,eAAe;AAInC,MAAI,EAFY,gBAAgB,eAAe,CAAC,aAAa,CAAC,OAG7D;AAID,MAAI,cAAc,QACjB,KAAI;AACH,iBAAc,QAAQ,MAAM;UACrB;EAMT,MAAM,SAAS,aAAa,oBAAoB;AAChD,SAAO,SAAS;AAChB,SAAO,OAAO;AACd,SAAO,aAAa,QAAQ;EAG5B,MAAM,WAAW,aAAa,YAAY;AAC1C,WAAS,KAAK,QAAQ;AAGtB,SAAO,QAAQ,SAAS;AACxB,WAAS,QAAQ,aAAa,YAAY;AAG1C,gBAAc,UAAU;AACxB,cAAY,UAAU;AAGtB,SAAO,gBAAgB;AACtB,OAAI,CAAC,KACJ,cAAa,MAAM;;AAKrB,SAAO,MAAM,EAAE;AACf,eAAa,KAAK;IAChB;EAAC;EAAM;EAAQ;EAAc;EAAW;EAAM,CAAC;CAGlD,MAAM,OAAO,kBAAkB;AAC9B,MAAI,cAAc,SAAS;AAC1B,OAAI;AACH,kBAAc,QAAQ,MAAM;AAC5B,kBAAc,QAAQ,YAAY;WAC3B;AAGR,iBAAc,UAAU;;AAEzB,eAAa,MAAM;IACjB,EAAE,CAAC;AAGN,uBACa;AACX,QAAM;IAEP,CAAC,KAAK,CACN;AAED,QAAO;EACN;EACA;EACA;EACA;EACA;EACA"}
@@ -0,0 +1,18 @@
1
+ //#region src/hooks/use-typing-sound.d.ts
2
+ /**
3
+ * Hook to play a looping typing sound while someone is typing.
4
+ *
5
+ * @param isTyping - Whether someone is currently typing
6
+ * @param options - Optional configuration for volume and playback speed
7
+ *
8
+ * @example
9
+ * const { isTyping } = useTypingIndicator();
10
+ * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });
11
+ */
12
+ declare function useTypingSound(isTyping: boolean, options?: {
13
+ volume?: number;
14
+ playbackRate?: number;
15
+ }): void;
16
+ //#endregion
17
+ export { useTypingSound };
18
+ //# sourceMappingURL=use-typing-sound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-typing-sound.d.ts","names":[],"sources":["../../src/hooks/use-typing-sound.ts"],"sourcesContent":[],"mappings":";;AAiBA;;;;;;;;;iBAAgB,cAAA"}
@@ -0,0 +1,38 @@
1
+ import { useSoundEffect } from "./use-sound-effect.js";
2
+ import { useEffect } from "react";
3
+
4
+ //#region src/hooks/use-typing-sound.ts
5
+ const TYPING_SOUND_PATH = "/sounds/typing-loop.wav";
6
+ /**
7
+ * Hook to play a looping typing sound while someone is typing.
8
+ *
9
+ * @param isTyping - Whether someone is currently typing
10
+ * @param options - Optional configuration for volume and playback speed
11
+ *
12
+ * @example
13
+ * const { isTyping } = useTypingIndicator();
14
+ * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });
15
+ */
16
+ function useTypingSound(isTyping, options) {
17
+ const { play, stop, isPlaying } = useSoundEffect(TYPING_SOUND_PATH, {
18
+ loop: true,
19
+ volume: options?.volume ?? 1.2,
20
+ playbackRate: options?.playbackRate ?? 1
21
+ });
22
+ useEffect(() => {
23
+ if (isTyping && !isPlaying) play();
24
+ else if (!isTyping && isPlaying) stop();
25
+ }, [
26
+ isTyping,
27
+ isPlaying,
28
+ play,
29
+ stop
30
+ ]);
31
+ useEffect(() => () => {
32
+ stop();
33
+ }, [stop]);
34
+ }
35
+
36
+ //#endregion
37
+ export { useTypingSound };
38
+ //# sourceMappingURL=use-typing-sound.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-typing-sound.js","names":[],"sources":["../../src/hooks/use-typing-sound.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useSoundEffect } from \"./use-sound-effect\";\n\n// Use a data URL or base64 encoded sound, or a CDN URL\n// For now, we'll use a path that can be served from public directory\nconst TYPING_SOUND_PATH = \"/sounds/typing-loop.wav\";\n\n/**\n * Hook to play a looping typing sound while someone is typing.\n *\n * @param isTyping - Whether someone is currently typing\n * @param options - Optional configuration for volume and playback speed\n *\n * @example\n * const { isTyping } = useTypingIndicator();\n * useTypingSound(isTyping, { volume: 1.0, playbackRate: 1.2 });\n */\nexport function useTypingSound(\n\tisTyping: boolean,\n\toptions?: { volume?: number; playbackRate?: number }\n): void {\n\tconst { play, stop, isPlaying } = useSoundEffect(TYPING_SOUND_PATH, {\n\t\tloop: true,\n\t\tvolume: options?.volume ?? 1.2,\n\t\tplaybackRate: options?.playbackRate ?? 1.0,\n\t});\n\n\tuseEffect(() => {\n\t\tif (isTyping && !isPlaying) {\n\t\t\tplay();\n\t\t} else if (!isTyping && isPlaying) {\n\t\t\tstop();\n\t\t}\n\t}, [isTyping, isPlaying, play, stop]);\n\n\t// Cleanup on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tstop();\n\t\t},\n\t\t[stop]\n\t);\n}\n"],"mappings":";;;;AAKA,MAAM,oBAAoB;;;;;;;;;;;AAY1B,SAAgB,eACf,UACA,SACO;CACP,MAAM,EAAE,MAAM,MAAM,cAAc,eAAe,mBAAmB;EACnE,MAAM;EACN,QAAQ,SAAS,UAAU;EAC3B,cAAc,SAAS,gBAAgB;EACvC,CAAC;AAEF,iBAAgB;AACf,MAAI,YAAY,CAAC,UAChB,OAAM;WACI,CAAC,YAAY,UACvB,OAAM;IAEL;EAAC;EAAU;EAAW;EAAM;EAAK,CAAC;AAGrC,uBACa;AACX,QAAM;IAEP,CAAC,KAAK,CACN"}
package/index.d.ts CHANGED
@@ -19,15 +19,17 @@ import { UseConversationsOptions, UseConversationsResult, useConversations } fro
19
19
  import { CreateConversationVariables, UseCreateConversationOptions, UseCreateConversationResult, useCreateConversation } from "./hooks/use-create-conversation.js";
20
20
  import { UseHomePageOptions, UseHomePageReturn, useHomePage } from "./hooks/use-home-page.js";
21
21
  import { UseMessageComposerOptions, UseMessageComposerReturn, useMessageComposer } from "./hooks/use-message-composer.js";
22
+ import { useNewMessageSound } from "./hooks/use-new-message-sound.js";
22
23
  import { UseRealtimeSupportOptions, UseRealtimeSupportResult, useRealtimeSupport } from "./hooks/use-realtime-support.js";
23
24
  import { UseScrollMaskOptions, UseScrollMaskReturn, useScrollMask } from "./hooks/use-scroll-mask.js";
24
25
  import { SendMessageOptions, SendMessageResult, UseSendMessageOptions, UseSendMessageResult, useSendMessage } from "./hooks/use-send-message.js";
26
+ import { UseSoundEffectOptions, UseSoundEffectReturn, useSoundEffect } from "./hooks/use-sound-effect.js";
27
+ import { useTypingSound } from "./hooks/use-typing-sound.js";
25
28
  import { UseVisitorReturn, useVisitor } from "./hooks/use-visitor.js";
26
29
  import { WindowVisibilityFocusState, useWindowVisibilityFocus } from "./hooks/use-window-visibility-focus.js";
27
30
  import "./hooks/index.js";
28
31
  import { IdentifySupportVisitor, IdentifySupportVisitorProps } from "./identify-visitor.js";
29
32
  import { SupportConfig, SupportConfigProps } from "./support-config.js";
30
- import { Page, PageProps } from "./primitives/page.js";
31
33
  import { index_d_exports } from "./primitives/index.js";
32
34
  import { CossistantContextValue, CossistantProviderProps, SupportContext, SupportProvider, SupportProviderProps, UseSupportValue, useSupport } from "./provider.js";
33
35
  import { RealtimeAuthConfig, RealtimeContextValue, RealtimeProvider, RealtimeProviderProps, useRealtimeConnection } from "./realtime/provider.js";
@@ -36,6 +38,7 @@ import { SupportRealtimeProvider } from "./realtime/support-provider.js";
36
38
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
37
39
  import { RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, useRealtime } from "./realtime/use-realtime.js";
38
40
  import "./realtime/index.js";
41
+ import { CustomPage } from "./support/router.js";
39
42
  import { Text, useSupportText } from "./support/text/index.js";
40
43
  import { BubbleSlotProps, ContainerSlotProps, RouterSlotProps } from "./support/types.js";
41
44
  import { CoButton } from "./support/components/button.js";
@@ -43,4 +46,4 @@ import { Header } from "./support/components/header.js";
43
46
  import { WebSocketContextValue, WebSocketProvider, useWebSocket } from "./support/context/websocket.js";
44
47
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
45
48
  import { DefaultRoutes, NavigationState, RouteRegistry, Support, SupportPage, SupportProps } from "./support/index.js";
46
- export { BubbleSlotProps, CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, ContainerSlotProps, ConversationItem, ConversationLifecycleState, ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, ConversationTimelineTypingParticipant, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, DefaultRoutes, GroupedMessage, Header, IdentifySupportVisitor, IdentifySupportVisitorProps, NavigationState, Page, PageProps, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, RouteRegistry, RouterSlotProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportContext, SupportLocale, SupportPage, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, TimelineToolItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationPreviewOptions, UseConversationPreviewReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationTimelineOptions, UseConversationTimelineReturn, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseScrollMaskOptions, UseScrollMaskReturn, UseSendMessageOptions, UseSendMessageResult, UseSupportValue, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
49
+ export { BubbleSlotProps, CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, ContainerSlotProps, ConversationItem, ConversationLifecycleState, ConversationPreviewAssignedAgent, ConversationPreviewLastMessage, ConversationPreviewTypingParticipant, ConversationPreviewTypingState, ConversationTimelineTypingParticipant, ConversationTypingParticipant, CossistantContextValue, CossistantProviderProps, CreateConversationVariables, CustomPage, DefaultRoutes, GroupedMessage, Header, IdentifySupportVisitor, IdentifySupportVisitorProps, NavigationState, index_d_exports as Primitives, RealtimeAuthConfig, RealtimeContextValue, RealtimeEventHandler, RealtimeEventHandlerEntry, RealtimeEventHandlersMap, RealtimeEventMeta, RealtimeProvider, RealtimeProviderProps, RouteRegistry, RouterSlotProps, SendMessageOptions, SendMessageResult, Support, SupportConfig, SupportConfigProps, SupportContext, SupportLocale, SupportPage, SupportProps, SupportProvider, SupportProviderProps, SupportRealtimeProvider, SupportTextContentOverrides, Text, TimelineEventItem, TimelineToolItem, UseClientResult, UseComposerRefocusOptions, UseComposerRefocusReturn, UseConversationAutoSeenOptions, UseConversationHistoryPageOptions, UseConversationHistoryPageReturn, UseConversationLifecycleOptions, UseConversationLifecycleReturn, UseConversationOptions, UseConversationPageOptions, UseConversationPageReturn, UseConversationPreviewOptions, UseConversationPreviewReturn, UseConversationResult, UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, UseConversationTimelineOptions, UseConversationTimelineReturn, UseConversationsOptions, UseConversationsResult, UseCreateConversationOptions, UseCreateConversationResult, UseGroupedMessagesOptions, UseGroupedMessagesProps, UseHomePageOptions, UseHomePageReturn, UseMessageComposerOptions, UseMessageComposerReturn, UseMultimodalInputOptions, UseMultimodalInputReturn, UseRealtimeSupportOptions, UseRealtimeSupportResult, UseScrollMaskOptions, UseScrollMaskReturn, UseSendMessageOptions, UseSendMessageResult, UseSoundEffectOptions, UseSoundEffectReturn, UseSupportValue, UseVisitorReturn, WebSocketContextValue, WebSocketProvider, WindowVisibilityFocusState, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useNewMessageSound, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSoundEffect, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useTypingSound, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/index.js CHANGED
@@ -1,15 +1,14 @@
1
1
  import { useClientQuery } from "./hooks/private/use-client-query.js";
2
2
  import { useClient } from "./hooks/private/use-rest-client.js";
3
3
  import { applyConversationSeenEvent, hydrateConversationSeen, upsertConversationSeen } from "./realtime/seen-store.js";
4
- import { SupportConfig } from "./support-config.js";
4
+ import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
5
5
  import { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState } from "./realtime/typing-store.js";
6
+ import { useRealtime } from "./realtime/use-realtime.js";
7
+ import { SupportRealtimeProvider } from "./realtime/support-provider.js";
8
+ import { SupportConfig } from "./support-config.js";
6
9
  import { useScrollMask } from "./hooks/use-scroll-mask.js";
7
- import { Page } from "./primitives/page.js";
8
10
  import { useSupportConfig, useSupportNavigation, useSupportStore } from "./support/store/support-store.js";
9
11
  import { primitives_exports } from "./primitives/index.js";
10
- import { RealtimeProvider, useRealtimeConnection } from "./realtime/provider.js";
11
- import { useRealtime } from "./realtime/use-realtime.js";
12
- import { SupportRealtimeProvider } from "./realtime/support-provider.js";
13
12
  import { CoButton } from "./support/components/button.js";
14
13
  import { Header } from "./support/components/header.js";
15
14
  import { Text, useSupportText } from "./support/text/index.js";
@@ -22,10 +21,13 @@ import { useMultimodalInput } from "./hooks/private/use-multimodal-input.js";
22
21
  import { useSendMessage } from "./hooks/use-send-message.js";
23
22
  import { useMessageComposer } from "./hooks/use-message-composer.js";
24
23
  import { useConversationPage } from "./hooks/use-conversation-page.js";
24
+ import { useSoundEffect } from "./hooks/use-sound-effect.js";
25
+ import { useNewMessageSound } from "./hooks/use-new-message-sound.js";
25
26
  import { useGroupedMessages } from "./hooks/private/use-grouped-messages.js";
26
27
  import { useConversationSeen, useDebouncedConversationSeen } from "./hooks/use-conversation-seen.js";
27
28
  import { useConversationTyping } from "./hooks/use-conversation-typing.js";
28
29
  import { useConversationTimeline } from "./hooks/use-conversation-timeline.js";
30
+ import { useTypingSound } from "./hooks/use-typing-sound.js";
29
31
  import { useComposerRefocus } from "./hooks/use-composer-refocus.js";
30
32
  import { useVisitor } from "./hooks/use-visitor.js";
31
33
  import { useConversations } from "./hooks/use-conversations.js";
@@ -40,4 +42,4 @@ import { useCreateConversation } from "./hooks/use-create-conversation.js";
40
42
  import { useRealtimeSupport } from "./hooks/use-realtime-support.js";
41
43
  import { IdentifySupportVisitor } from "./identify-visitor.js";
42
44
 
43
- export { CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, Header, IdentifySupportVisitor, Page, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportContext, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useVisitor, useWebSocket, useWindowVisibilityFocus };
45
+ export { CoButton as Button, CONVERSATION_AUTO_SEEN_DELAY_MS, Header, IdentifySupportVisitor, primitives_exports as Primitives, RealtimeProvider, Support, SupportConfig, SupportContext, SupportProvider, SupportRealtimeProvider, Text, WebSocketProvider, applyConversationSeenEvent, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, hydrateConversationSeen, setTypingState, upsertConversationSeen, useClient, useClientQuery, useComposerRefocus, useConversation, useConversationAutoSeen, useConversationHistoryPage, useConversationLifecycle, useConversationPage, useConversationPreview, useConversationSeen, useConversationTimeline, useConversationTimelineItems, useConversationTyping, useConversations, useCreateConversation, useDebouncedConversationSeen, useDefaultMessages, useGroupedMessages, useHomePage, useMessageComposer, useMultimodalInput, useNewMessageSound, useRealtime, useRealtimeConnection, useRealtimeSupport, useScrollMask, useSendMessage, useSoundEffect, useSupport, useSupportConfig, useSupportNavigation, useSupportStore, useSupportText, useTypingSound, useVisitor, useWebSocket, useWindowVisibilityFocus };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cossistant/react",
3
3
  "type": "module",
4
- "version": "0.0.19",
4
+ "version": "0.0.22",
5
5
  "private": false,
6
6
  "author": "Cossistant team",
7
7
  "description": "Headless React SDK for building AI-powered support/chat widgets. Hooks + primitives, WS-driven, TypeScript-first. Next.js-ready, Tailwind optional.",
@@ -88,8 +88,8 @@
88
88
  "*.css"
89
89
  ],
90
90
  "dependencies": {
91
- "@cossistant/core": "0.0.19",
92
- "@cossistant/types": "0.0.19",
91
+ "@cossistant/core": "0.0.22",
92
+ "@cossistant/types": "0.0.22",
93
93
  "class-variance-authority": "^0.7.1",
94
94
  "clsx": "^2.1.1",
95
95
  "nanoid": "^5.1.5",
@@ -15,7 +15,7 @@ type AvatarImageProps = Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "src"
15
15
  * Controlled `<img>` that syncs its loading status back to the avatar context
16
16
  * so fallbacks know when to display.
17
17
  */
18
- declare const AvatarImage: React$1.ForwardRefExoticComponent<Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "alt" | "src"> & {
18
+ declare const AvatarImage: React$1.ForwardRefExoticComponent<Omit<React$1.ImgHTMLAttributes<HTMLImageElement>, "src" | "alt"> & {
19
19
  src: string;
20
20
  alt?: string;
21
21
  asChild?: boolean;
@@ -1,5 +1,5 @@
1
- import { useRenderElement } from "../utils/use-render-element.js";
2
1
  import { useTypingStore } from "../realtime/typing-store.js";
2
+ import { useRenderElement } from "../utils/use-render-element.js";
3
3
  import { useSupportConfig } from "../support/store/support-store.js";
4
4
  import { useSupport } from "../provider.js";
5
5
  import * as React$1 from "react";
@@ -7,9 +7,7 @@ import { SupportBubble } from "./bubble.js";
7
7
  import { Button } from "./button.js";
8
8
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
9
9
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
10
- import { Page, PageProps } from "./page.js";
11
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
12
- import { Router, RouterProps } from "./router.js";
10
+ import { PageDefinition, Router, RouterProps } from "./router.js";
13
11
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
14
12
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
15
13
  import { SupportWindow } from "./window.js";
@@ -17,8 +15,8 @@ import "./index.parts.js";
17
15
 
18
16
  //#region src/primitives/index.d.ts
19
17
  declare namespace index_d_exports {
20
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
18
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, PageDefinition, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window };
21
19
  }
22
20
  //#endregion
23
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageProps, PageRegistryProvider, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports, usePageRegistry, useRegisterPage };
21
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, PageDefinition, Router, RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, TypingIndicatorProps, TypingParticipant, TypingParticipantType, SupportWindow as Window, index_d_exports };
24
22
  //# sourceMappingURL=index.d.ts.map
@@ -1,15 +1,13 @@
1
1
  import { __export } from "../_virtual/rolldown_runtime.js";
2
+ import { SupportConfig } from "../support-config.js";
2
3
  import { Avatar } from "./avatar/avatar.js";
3
4
  import { AvatarFallback } from "./avatar/fallback.js";
4
5
  import { AvatarImage } from "./avatar/image.js";
5
6
  import { TypingIndicator } from "../support/components/typing-indicator.js";
6
- import { SupportConfig } from "../support-config.js";
7
7
  import { SupportBubble } from "./bubble.js";
8
8
  import { Button } from "./button.js";
9
9
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
10
10
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
11
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
12
- import { Page } from "./page.js";
13
11
  import { Router } from "./router.js";
14
12
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
15
13
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
@@ -30,8 +28,6 @@ var primitives_exports = /* @__PURE__ */ __export({
30
28
  FileInput: () => FileInput,
31
29
  Input: () => SupportInput,
32
30
  MultimodalInput: () => MultimodalInput,
33
- Page: () => Page,
34
- PageRegistryProvider: () => PageRegistryProvider,
35
31
  Router: () => Router,
36
32
  TimelineItem: () => TimelineItem,
37
33
  TimelineItemContent: () => TimelineItemContent,
@@ -43,11 +39,9 @@ var primitives_exports = /* @__PURE__ */ __export({
43
39
  TimelineItemGroupSeenIndicator: () => TimelineItemGroupSeenIndicator,
44
40
  TimelineItemTimestamp: () => TimelineItemTimestamp,
45
41
  TypingIndicator: () => TypingIndicator,
46
- Window: () => SupportWindow,
47
- usePageRegistry: () => usePageRegistry,
48
- useRegisterPage: () => useRegisterPage
42
+ Window: () => SupportWindow
49
43
  });
50
44
 
51
45
  //#endregion
52
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, PageRegistryProvider, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports, usePageRegistry, useRegisterPage };
46
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Router, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, SupportWindow as Window, primitives_exports };
53
47
  //# sourceMappingURL=index.js.map
@@ -8,10 +8,8 @@ import { SupportBubble } from "./bubble.js";
8
8
  import { Button } from "./button.js";
9
9
  import { ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading } from "./conversation-timeline.js";
10
10
  import { FileInput, MultimodalInput, SupportInput } from "./multimodal-input.js";
11
- import { Page, PageProps } from "./page.js";
12
- import { PageRegistryProvider, usePageRegistry, useRegisterPage } from "./page-registry.js";
13
- import { Router, RouterProps } from "./router.js";
11
+ import { PageDefinition, Router, RouterProps } from "./router.js";
14
12
  import { TimelineItem, TimelineItemContent, TimelineItemTimestamp } from "./timeline-item.js";
15
13
  import { TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator } from "./timeline-item-group.js";
16
14
  import { SupportWindow } from "./window.js";
17
- export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, Page, type PageProps, PageRegistryProvider, Router, type RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window, usePageRegistry, useRegisterPage };
15
+ export { Avatar, AvatarFallback, AvatarImage, SupportBubble as Bubble, Button, SupportConfig as Config, ConversationTimeline, ConversationTimelineContainer, ConversationTimelineEmpty, ConversationTimelineLoading, FileInput, SupportInput as Input, MultimodalInput, type PageDefinition, Router, type RouterProps, TimelineItem, TimelineItemContent, TimelineItemGroup, TimelineItemGroupAvatar, TimelineItemGroupContent, TimelineItemGroupHeader, TimelineItemGroupReadIndicator, TimelineItemGroupSeenIndicator, TimelineItemTimestamp, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType, SupportWindow as Window };