@cossistant/react 0.0.4 → 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.
- package/_virtual/rolldown_runtime.js +19 -0
- package/conversation.d.ts +26 -3
- package/conversation.d.ts.map +1 -1
- package/hooks/index.d.ts +5 -3
- package/hooks/index.js +7 -5
- package/hooks/private/store/use-conversations-store.d.ts +8 -0
- package/hooks/private/store/use-conversations-store.d.ts.map +1 -1
- package/hooks/private/store/use-conversations-store.js +8 -0
- package/hooks/private/store/use-conversations-store.js.map +1 -1
- package/hooks/private/store/use-store-selector.d.ts +4 -0
- package/hooks/private/store/use-store-selector.d.ts.map +1 -1
- package/hooks/private/store/use-store-selector.js +5 -2
- package/hooks/private/store/use-store-selector.js.map +1 -1
- package/hooks/private/store/use-website-store.d.ts +4 -0
- package/hooks/private/store/use-website-store.d.ts.map +1 -1
- package/hooks/private/store/use-website-store.js +6 -3
- package/hooks/private/store/use-website-store.js.map +1 -1
- package/hooks/private/typing.d.ts +35 -0
- package/hooks/private/typing.d.ts.map +1 -0
- package/hooks/private/typing.js +49 -0
- package/hooks/private/typing.js.map +1 -0
- package/hooks/private/use-client-query.d.ts +5 -0
- package/hooks/private/use-client-query.d.ts.map +1 -1
- package/hooks/private/use-client-query.js +5 -0
- package/hooks/private/use-client-query.js.map +1 -1
- package/hooks/private/use-grouped-messages.d.ts +10 -4
- package/hooks/private/use-grouped-messages.d.ts.map +1 -1
- package/hooks/private/use-grouped-messages.js +24 -4
- package/hooks/private/use-grouped-messages.js.map +1 -1
- package/hooks/private/use-multimodal-input.d.ts.map +1 -1
- package/hooks/private/use-rest-client.d.ts.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.d.ts +6 -0
- package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.js +6 -0
- package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
- package/hooks/use-composer-refocus.d.ts.map +1 -1
- package/hooks/use-conversation-auto-seen.d.ts +9 -0
- package/hooks/use-conversation-auto-seen.d.ts.map +1 -1
- package/hooks/use-conversation-auto-seen.js +44 -3
- package/hooks/use-conversation-auto-seen.js.map +1 -1
- package/hooks/use-conversation-history-page.d.ts.map +1 -1
- package/hooks/use-conversation-history-page.js +16 -18
- package/hooks/use-conversation-history-page.js.map +1 -1
- package/hooks/use-conversation-lifecycle.d.ts.map +1 -1
- package/hooks/use-conversation-lifecycle.js +2 -4
- package/hooks/use-conversation-lifecycle.js.map +1 -1
- package/hooks/use-conversation-page.d.ts +6 -0
- package/hooks/use-conversation-page.d.ts.map +1 -1
- package/hooks/use-conversation-page.js +41 -3
- package/hooks/use-conversation-page.js.map +1 -1
- package/hooks/use-conversation-preview.d.ts +61 -0
- package/hooks/use-conversation-preview.d.ts.map +1 -0
- package/hooks/use-conversation-preview.js +173 -0
- package/hooks/use-conversation-preview.js.map +1 -0
- package/hooks/use-conversation-seen.d.ts +4 -0
- package/hooks/use-conversation-seen.d.ts.map +1 -1
- package/hooks/use-conversation-seen.js +4 -0
- package/hooks/use-conversation-seen.js.map +1 -1
- package/hooks/use-conversation-timeline-items.d.ts +4 -0
- package/hooks/use-conversation-timeline-items.d.ts.map +1 -1
- package/hooks/use-conversation-timeline-items.js +4 -0
- package/hooks/use-conversation-timeline-items.js.map +1 -1
- package/hooks/use-conversation-timeline.d.ts +32 -0
- package/hooks/use-conversation-timeline.d.ts.map +1 -0
- package/hooks/use-conversation-timeline.js +41 -0
- package/hooks/use-conversation-timeline.js.map +1 -0
- package/hooks/use-conversation-typing.d.ts +4 -0
- package/hooks/use-conversation-typing.d.ts.map +1 -1
- package/hooks/use-conversation-typing.js +4 -0
- package/hooks/use-conversation-typing.js.map +1 -1
- package/hooks/use-conversation.d.ts +11 -0
- package/hooks/use-conversation.d.ts.map +1 -1
- package/hooks/use-conversation.js +11 -0
- package/hooks/use-conversation.js.map +1 -1
- package/hooks/use-conversations.d.ts +12 -0
- package/hooks/use-conversations.d.ts.map +1 -1
- package/hooks/use-conversations.js +12 -0
- package/hooks/use-conversations.js.map +1 -1
- package/hooks/use-create-conversation.d.ts +5 -0
- package/hooks/use-create-conversation.d.ts.map +1 -1
- package/hooks/use-create-conversation.js +12 -9
- package/hooks/use-create-conversation.js.map +1 -1
- package/hooks/use-home-page.d.ts.map +1 -1
- package/hooks/use-home-page.js +6 -4
- package/hooks/use-home-page.js.map +1 -1
- package/hooks/use-message-composer.d.ts.map +1 -1
- package/hooks/use-realtime-support.d.ts.map +1 -1
- package/hooks/use-send-message.d.ts +9 -0
- package/hooks/use-send-message.d.ts.map +1 -1
- package/hooks/use-send-message.js +15 -13
- package/hooks/use-send-message.js.map +1 -1
- package/hooks/use-visitor.d.ts.map +1 -1
- package/hooks/use-visitor.js +28 -30
- package/hooks/use-visitor.js.map +1 -1
- package/hooks/use-window-visibility-focus.d.ts +4 -0
- package/hooks/use-window-visibility-focus.d.ts.map +1 -1
- package/hooks/use-window-visibility-focus.js +5 -2
- package/hooks/use-window-visibility-focus.js.map +1 -1
- package/identify-visitor.d.ts +12 -3
- package/identify-visitor.d.ts.map +1 -1
- package/identify-visitor.js +58 -9
- package/identify-visitor.js.map +1 -1
- package/index.d.ts +10 -7
- package/index.js +10 -9
- package/package.json +11 -16
- package/primitives/avatar/avatar.d.ts.map +1 -1
- package/primitives/avatar/fallback.d.ts.map +1 -1
- package/primitives/avatar/fallback.js +1 -3
- package/primitives/avatar/fallback.js.map +1 -1
- package/primitives/avatar/image.d.ts.map +1 -1
- package/primitives/avatar/index.d.ts +1 -0
- package/primitives/bubble.d.ts +2 -0
- package/primitives/bubble.d.ts.map +1 -1
- package/primitives/bubble.js +8 -2
- package/primitives/bubble.js.map +1 -1
- package/primitives/button.d.ts.map +1 -1
- package/primitives/conversation-timeline.d.ts.map +1 -1
- package/primitives/conversation-timeline.js +58 -5
- package/primitives/conversation-timeline.js.map +1 -1
- package/primitives/index.d.ts +1 -0
- package/primitives/index.parts.d.ts +1 -0
- package/primitives/multimodal-input.d.ts.map +1 -1
- package/primitives/timeline-item-group.d.ts +7 -7
- package/primitives/timeline-item-group.d.ts.map +1 -1
- package/primitives/timeline-item-group.js.map +1 -1
- package/primitives/timeline-item.d.ts +1 -1
- package/primitives/timeline-item.d.ts.map +1 -1
- package/primitives/timeline-item.js +7 -1
- package/primitives/timeline-item.js.map +1 -1
- package/primitives/window.d.ts +1 -1
- package/primitives/window.d.ts.map +1 -1
- package/primitives/window.js +4 -4
- package/primitives/window.js.map +1 -1
- package/provider.d.ts +23 -43
- package/provider.d.ts.map +1 -1
- package/provider.js +152 -49
- package/provider.js.map +1 -1
- package/realtime/event-filter.d.ts +4 -0
- package/realtime/event-filter.d.ts.map +1 -1
- package/realtime/event-filter.js +4 -0
- package/realtime/event-filter.js.map +1 -1
- package/realtime/index.js +1 -1
- package/realtime/provider.d.ts +7 -2
- package/realtime/provider.d.ts.map +1 -1
- package/realtime/provider.js +23 -1
- package/realtime/provider.js.map +1 -1
- package/realtime/seen-store.d.ts +13 -0
- package/realtime/seen-store.d.ts.map +1 -1
- package/realtime/seen-store.js +14 -2
- package/realtime/seen-store.js.map +1 -1
- package/realtime/support-provider.d.ts +1 -2
- package/realtime/support-provider.d.ts.map +1 -1
- package/realtime/support-provider.js +19 -20
- package/realtime/support-provider.js.map +1 -1
- package/realtime/typing-store.d.ts +18 -0
- package/realtime/typing-store.d.ts.map +1 -1
- package/realtime/typing-store.js +19 -2
- package/realtime/typing-store.js.map +1 -1
- package/realtime/use-realtime.d.ts +8 -4
- package/realtime/use-realtime.d.ts.map +1 -1
- package/realtime/use-realtime.js +4 -0
- package/realtime/use-realtime.js.map +1 -1
- package/realtime-events.d.ts +17 -3
- package/realtime-events.d.ts.map +1 -1
- package/schemas.d.ts +7 -1
- package/schemas.d.ts.map +1 -1
- package/support/components/avatar-stack.d.ts +8 -4
- package/support/components/avatar-stack.d.ts.map +1 -1
- package/support/components/avatar-stack.js +4 -0
- package/support/components/avatar-stack.js.map +1 -1
- package/support/components/avatar.d.ts +11 -6
- package/support/components/avatar.d.ts.map +1 -1
- package/support/components/avatar.js +4 -0
- package/support/components/avatar.js.map +1 -1
- package/support/components/bubble.d.ts.map +1 -1
- package/support/components/bubble.js +29 -6
- package/support/components/bubble.js.map +1 -1
- package/support/components/button.d.ts +8 -5
- package/support/components/button.d.ts.map +1 -1
- package/support/components/button.js +5 -1
- package/support/components/button.js.map +1 -1
- package/support/components/container.d.ts +0 -1
- package/support/components/container.d.ts.map +1 -1
- package/support/components/container.js +2 -8
- package/support/components/container.js.map +1 -1
- package/support/components/conversation-button-link.d.ts +8 -21
- package/support/components/conversation-button-link.d.ts.map +1 -1
- package/support/components/conversation-button-link.js +62 -178
- package/support/components/conversation-button-link.js.map +1 -1
- package/support/components/conversation-event.d.ts.map +1 -1
- package/support/components/conversation-event.js +4 -0
- package/support/components/conversation-event.js.map +1 -1
- package/support/components/conversation-timeline.d.ts +10 -1
- package/support/components/conversation-timeline.d.ts.map +1 -1
- package/support/components/conversation-timeline.js +63 -57
- package/support/components/conversation-timeline.js.map +1 -1
- package/support/components/cossistant-branding.d.ts +5 -2
- package/support/components/cossistant-branding.d.ts.map +1 -1
- package/support/components/cossistant-branding.js +3 -0
- package/support/components/cossistant-branding.js.map +1 -1
- package/support/components/header.d.ts.map +1 -1
- package/support/components/header.js +2 -2
- package/support/components/header.js.map +1 -1
- package/support/components/icons.d.ts.map +1 -1
- package/support/components/multimodal-input.d.ts.map +1 -1
- package/support/components/multimodal-input.js +5 -24
- package/support/components/multimodal-input.js.map +1 -1
- package/support/components/navigation-tab.d.ts +7 -2
- package/support/components/navigation-tab.d.ts.map +1 -1
- package/support/components/navigation-tab.js +4 -0
- package/support/components/navigation-tab.js.map +1 -1
- package/support/components/support-content.d.ts +1 -1
- package/support/components/support-content.d.ts.map +1 -1
- package/support/components/support-content.js +7 -10
- package/support/components/support-content.js.map +1 -1
- package/support/components/text-effect.d.ts +5 -2
- package/support/components/text-effect.d.ts.map +1 -1
- package/support/components/text-effect.js +4 -0
- package/support/components/text-effect.js.map +1 -1
- package/support/components/timeline-identification-tool.d.ts +7 -0
- package/support/components/timeline-identification-tool.d.ts.map +1 -0
- package/support/components/timeline-identification-tool.js +139 -0
- package/support/components/timeline-identification-tool.js.map +1 -0
- package/support/components/timeline-message-group.d.ts +2 -1
- package/support/components/timeline-message-group.d.ts.map +1 -1
- package/support/components/timeline-message-group.js +4 -19
- package/support/components/timeline-message-group.js.map +1 -1
- package/support/components/timeline-message-item.d.ts +6 -2
- package/support/components/timeline-message-item.d.ts.map +1 -1
- package/support/components/timeline-message-item.js +8 -4
- package/support/components/timeline-message-item.js.map +1 -1
- package/support/components/typing-indicator.d.ts +5 -2
- package/support/components/typing-indicator.d.ts.map +1 -1
- package/support/components/typing-indicator.js +4 -4
- package/support/components/typing-indicator.js.map +1 -1
- package/support/components/watermark.d.ts.map +1 -1
- package/support/context/websocket.d.ts +8 -0
- package/support/context/websocket.d.ts.map +1 -1
- package/support/context/websocket.js +12 -6
- package/support/context/websocket.js.map +1 -1
- package/support/index.d.ts +8 -8
- package/support/index.d.ts.map +1 -1
- package/support/index.js +18 -18
- package/support/index.js.map +1 -1
- package/support/pages/conversation-history.js +46 -54
- package/support/pages/conversation-history.js.map +1 -1
- package/support/pages/conversation.d.ts +3 -6
- package/support/pages/conversation.d.ts.map +1 -1
- package/support/pages/conversation.js +19 -9
- package/support/pages/conversation.js.map +1 -1
- package/support/pages/home.d.ts +2 -2
- package/support/pages/home.d.ts.map +1 -1
- package/support/pages/home.js +64 -77
- package/support/pages/home.js.map +1 -1
- package/support/store/support-store.d.ts +18 -2
- package/support/store/support-store.d.ts.map +1 -1
- package/support/store/support-store.js +20 -5
- package/support/store/support-store.js.map +1 -1
- package/support/{support-CMoDLQoC.css → support-Ck4jy29i.css} +1 -2
- package/support/support-Ck4jy29i.css.map +1 -0
- package/support/text/index.d.ts +15 -2
- package/support/text/index.d.ts.map +1 -1
- package/support/text/index.js +15 -2
- package/support/text/index.js.map +1 -1
- package/support/text/locales/en.js +22 -4
- package/support/text/locales/en.js.map +1 -1
- package/support/text/locales/es.js +18 -0
- package/support/text/locales/es.js.map +1 -1
- package/support/text/locales/fr.js +18 -0
- package/support/text/locales/fr.js.map +1 -1
- package/support/text/locales/keys.d.ts +69 -9
- package/support/text/locales/keys.d.ts.map +1 -1
- package/support/text/locales/keys.js +18 -0
- package/support/text/locales/keys.js.map +1 -1
- package/support/text/runtime.d.ts +21 -0
- package/support/text/runtime.d.ts.map +1 -1
- package/support/text/runtime.js +21 -0
- package/support/text/runtime.js.map +1 -1
- package/support/utils/index.d.ts +4 -0
- package/support/utils/index.d.ts.map +1 -1
- package/support/utils/index.js +4 -1
- package/support/utils/index.js.map +1 -1
- package/support/utils/time.d.ts +3 -0
- package/support/utils/time.d.ts.map +1 -1
- package/support/utils/time.js +3 -0
- package/support/utils/time.js.map +1 -1
- package/support-config.d.ts +2 -1
- package/support-config.d.ts.map +1 -1
- package/support-config.js.map +1 -1
- package/support.css +2 -2
- package/timeline-item.d.ts +10 -0
- package/timeline-item.d.ts.map +1 -1
- package/utils/conversation.d.ts +7 -0
- package/utils/conversation.d.ts.map +1 -0
- package/utils/conversation.js +18 -0
- package/utils/conversation.js.map +1 -0
- package/utils/id.d.ts +3 -0
- package/utils/id.d.ts.map +1 -1
- package/utils/id.js +3 -0
- package/utils/id.js.map +1 -1
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/metadata-hash.d.ts +12 -0
- package/utils/metadata-hash.d.ts.map +1 -0
- package/utils/metadata-hash.js +26 -0
- package/utils/metadata-hash.js.map +1 -0
- package/utils/text.d.ts +3 -0
- package/utils/text.d.ts.map +1 -1
- package/utils/text.js +3 -0
- package/utils/text.js.map +1 -1
- package/utils/use-render-element.d.ts +3 -0
- package/utils/use-render-element.d.ts.map +1 -1
- package/utils/use-render-element.js +3 -0
- package/utils/use-render-element.js.map +1 -1
- package/support/context/config.d.ts +0 -32
- package/support/context/config.d.ts.map +0 -1
- package/support/context/config.js +0 -27
- package/support/context/config.js.map +0 -1
- package/support/support-CMoDLQoC.css.map +0 -1
package/realtime/seen-store.d.ts
CHANGED
|
@@ -5,14 +5,27 @@ import { SeenActorType, SeenState } from "@cossistant/core";
|
|
|
5
5
|
//#region src/realtime/seen-store.d.ts
|
|
6
6
|
type Selector<T> = (state: SeenState) => T;
|
|
7
7
|
type EqualityChecker<T> = (previous: T, next: T) => boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Public hook for subscribing to slices of the shared "seen" store.
|
|
10
|
+
*/
|
|
8
11
|
declare function useSeenStore<TSelected>(selector: Selector<TSelected>, isEqual?: EqualityChecker<TSelected>): TSelected;
|
|
12
|
+
/**
|
|
13
|
+
* Seeds the seen store with initial data, typically from the REST API or SSR.
|
|
14
|
+
*/
|
|
9
15
|
declare function hydrateConversationSeen(conversationId: string, entries: ConversationSeen[]): void;
|
|
16
|
+
/**
|
|
17
|
+
* Inserts or updates a seen entry for the provided actor.
|
|
18
|
+
*/
|
|
10
19
|
declare function upsertConversationSeen(options: {
|
|
11
20
|
conversationId: string;
|
|
12
21
|
actorType: SeenActorType;
|
|
13
22
|
actorId: string;
|
|
14
23
|
lastSeenAt: Date;
|
|
15
24
|
}): void;
|
|
25
|
+
/**
|
|
26
|
+
* Applies realtime `conversationSeen` events to the store while optionally
|
|
27
|
+
* ignoring the local visitor/user.
|
|
28
|
+
*/
|
|
16
29
|
declare function applyConversationSeenEvent(event: RealtimeEvent<"conversationSeen">, options?: {
|
|
17
30
|
ignoreVisitorId?: string | null;
|
|
18
31
|
ignoreUserId?: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seen-store.d.ts","names":[],"sources":["../../src/realtime/seen-store.ts"],"sourcesContent":[],"mappings":";;;;;KAeK,sBAAsB,cAAc;KAEpC,gCAAgC,SAAS;
|
|
1
|
+
{"version":3,"file":"seen-store.d.ts","names":[],"sources":["../../src/realtime/seen-store.ts"],"sourcesContent":[],"mappings":";;;;;KAeK,sBAAsB,cAAc;KAEpC,gCAAgC,SAAS;AAPoB;AAKxB;AAoC1C;AACoB,iBADJ,YACI,CAAA,SAAA,CAAA,CAAA,QAAA,EAAT,QAAS,CAAA,SAAA,CAAA,EAAA,OAAA,CAAA,EACT,eADS,CACO,SADP,CAAA,CAAA,EAEjB,SAFiB;;;;AAEjB,iBAOa,uBAAA,CAPb,cAAA,EAAA,MAAA,EAAA,OAAA,EASO,gBATP,EAAA,CAAA,EAAA,IAAA;;AAOH;AAUA;AAgBgB,iBAhBA,sBAAA,CAiBR,OAAA,EAAA;;aAfI;;cAEC;;;;;;iBAYG,0BAAA,QACR"}
|
package/realtime/seen-store.js
CHANGED
|
@@ -8,23 +8,35 @@ function useSelector(selector, isEqual = Object.is) {
|
|
|
8
8
|
const subscribe = (onStoreChange) => store.subscribe(() => {
|
|
9
9
|
onStoreChange();
|
|
10
10
|
});
|
|
11
|
-
const
|
|
12
|
-
const selected = selector(snapshot);
|
|
11
|
+
const selected = selector(useSyncExternalStore(subscribe, store.getState, store.getState));
|
|
13
12
|
if (selectionRef.current === void 0 || !isEqual(selectionRef.current, selected)) selectionRef.current = selected;
|
|
14
13
|
return selectionRef.current;
|
|
15
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Public hook for subscribing to slices of the shared "seen" store.
|
|
17
|
+
*/
|
|
16
18
|
function useSeenStore(selector, isEqual) {
|
|
17
19
|
return useSelector(selector, isEqual);
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Seeds the seen store with initial data, typically from the REST API or SSR.
|
|
23
|
+
*/
|
|
19
24
|
function hydrateConversationSeen(conversationId, entries) {
|
|
20
25
|
hydrateConversationSeen$1(store, conversationId, entries);
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Inserts or updates a seen entry for the provided actor.
|
|
29
|
+
*/
|
|
22
30
|
function upsertConversationSeen(options) {
|
|
23
31
|
upsertConversationSeen$1(store, {
|
|
24
32
|
...options,
|
|
25
33
|
lastSeenAt: options.lastSeenAt.toISOString()
|
|
26
34
|
});
|
|
27
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Applies realtime `conversationSeen` events to the store while optionally
|
|
38
|
+
* ignoring the local visitor/user.
|
|
39
|
+
*/
|
|
28
40
|
function applyConversationSeenEvent(event, options) {
|
|
29
41
|
applyConversationSeenEvent$1(store, event, options);
|
|
30
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seen-store.js","names":[],"sources":["../../src/realtime/seen-store.ts"],"sourcesContent":["import {\n\tapplyConversationSeenEvent as applyEvent,\n\tcreateSeenStore,\n\thydrateConversationSeen as hydrateStore,\n\ttype SeenActorType,\n\ttype SeenEntry,\n\ttype SeenState,\n\tupsertConversationSeen as upsertStore,\n} from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type { ConversationSeen } from \"@cossistant/types/schemas\";\nimport { useRef, useSyncExternalStore } from \"react\";\n\nconst store = createSeenStore();\n\ntype Selector<T> = (state: SeenState) => T;\n\ntype EqualityChecker<T> = (previous: T, next: T) => boolean;\n\nfunction useSelector<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual: EqualityChecker<TSelected> = Object.is\n): TSelected {\n\tconst selectionRef = useRef<TSelected>(undefined);\n\n\tconst subscribe = (onStoreChange: () => void) =>\n\t\tstore.subscribe(() => {\n\t\t\tonStoreChange();\n\t\t});\n\n\tconst snapshot = useSyncExternalStore(\n\t\tsubscribe,\n\t\tstore.getState,\n\t\tstore.getState\n\t);\n\n\tconst selected = selector(snapshot);\n\n\tif (\n\t\tselectionRef.current === undefined ||\n\t\t!isEqual(selectionRef.current, selected)\n\t) {\n\t\tselectionRef.current = selected;\n\t}\n\n\treturn selectionRef.current as TSelected;\n}\n\nexport function useSeenStore<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual?: EqualityChecker<TSelected>\n): TSelected {\n\treturn useSelector(selector, isEqual);\n}\n\nexport function hydrateConversationSeen(\n\tconversationId: string,\n\tentries: ConversationSeen[]\n) {\n\thydrateStore(store, conversationId, entries);\n}\n\nexport function upsertConversationSeen(options: {\n\tconversationId: string;\n\tactorType: SeenActorType;\n\tactorId: string;\n\tlastSeenAt: Date;\n}) {\n\tupsertStore(store, {\n\t\t...options,\n\t\tlastSeenAt: options.lastSeenAt.toISOString(),\n\t});\n}\n\nexport function applyConversationSeenEvent(\n\tevent: RealtimeEvent<\"conversationSeen\">,\n\toptions?: {\n\t\tignoreVisitorId?: string | null;\n\t\tignoreUserId?: string | null;\n\t\tignoreAiAgentId?: string | null;\n\t}\n) {\n\tapplyEvent(store, event, options);\n}\n"],"mappings":";;;;AAaA,MAAM,QAAQ,iBAAiB;AAM/B,SAAS,YACR,UACA,UAAsC,OAAO,IACjC;CACZ,MAAM,eAAe,OAAkB,OAAU;CAEjD,MAAM,aAAa,kBAClB,MAAM,gBAAgB;AACrB,iBAAe;GACd;
|
|
1
|
+
{"version":3,"file":"seen-store.js","names":[],"sources":["../../src/realtime/seen-store.ts"],"sourcesContent":["import {\n\tapplyConversationSeenEvent as applyEvent,\n\tcreateSeenStore,\n\thydrateConversationSeen as hydrateStore,\n\ttype SeenActorType,\n\ttype SeenEntry,\n\ttype SeenState,\n\tupsertConversationSeen as upsertStore,\n} from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type { ConversationSeen } from \"@cossistant/types/schemas\";\nimport { useRef, useSyncExternalStore } from \"react\";\n\nconst store = createSeenStore();\n\ntype Selector<T> = (state: SeenState) => T;\n\ntype EqualityChecker<T> = (previous: T, next: T) => boolean;\n\nfunction useSelector<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual: EqualityChecker<TSelected> = Object.is\n): TSelected {\n\tconst selectionRef = useRef<TSelected>(undefined);\n\n\tconst subscribe = (onStoreChange: () => void) =>\n\t\tstore.subscribe(() => {\n\t\t\tonStoreChange();\n\t\t});\n\n\tconst snapshot = useSyncExternalStore(\n\t\tsubscribe,\n\t\tstore.getState,\n\t\tstore.getState\n\t);\n\n\tconst selected = selector(snapshot);\n\n\tif (\n\t\tselectionRef.current === undefined ||\n\t\t!isEqual(selectionRef.current, selected)\n\t) {\n\t\tselectionRef.current = selected;\n\t}\n\n\treturn selectionRef.current as TSelected;\n}\n\n/**\n * Public hook for subscribing to slices of the shared \"seen\" store.\n */\nexport function useSeenStore<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual?: EqualityChecker<TSelected>\n): TSelected {\n\treturn useSelector(selector, isEqual);\n}\n\n/**\n * Seeds the seen store with initial data, typically from the REST API or SSR.\n */\nexport function hydrateConversationSeen(\n\tconversationId: string,\n\tentries: ConversationSeen[]\n) {\n\thydrateStore(store, conversationId, entries);\n}\n\n/**\n * Inserts or updates a seen entry for the provided actor.\n */\nexport function upsertConversationSeen(options: {\n\tconversationId: string;\n\tactorType: SeenActorType;\n\tactorId: string;\n\tlastSeenAt: Date;\n}) {\n\tupsertStore(store, {\n\t\t...options,\n\t\tlastSeenAt: options.lastSeenAt.toISOString(),\n\t});\n}\n\n/**\n * Applies realtime `conversationSeen` events to the store while optionally\n * ignoring the local visitor/user.\n */\nexport function applyConversationSeenEvent(\n\tevent: RealtimeEvent<\"conversationSeen\">,\n\toptions?: {\n\t\tignoreVisitorId?: string | null;\n\t\tignoreUserId?: string | null;\n\t\tignoreAiAgentId?: string | null;\n\t}\n) {\n\tapplyEvent(store, event, options);\n}\n"],"mappings":";;;;AAaA,MAAM,QAAQ,iBAAiB;AAM/B,SAAS,YACR,UACA,UAAsC,OAAO,IACjC;CACZ,MAAM,eAAe,OAAkB,OAAU;CAEjD,MAAM,aAAa,kBAClB,MAAM,gBAAgB;AACrB,iBAAe;GACd;CAQH,MAAM,WAAW,SANA,qBAChB,WACA,MAAM,UACN,MAAM,SACN,CAEkC;AAEnC,KACC,aAAa,YAAY,UACzB,CAAC,QAAQ,aAAa,SAAS,SAAS,CAExC,cAAa,UAAU;AAGxB,QAAO,aAAa;;;;;AAMrB,SAAgB,aACf,UACA,SACY;AACZ,QAAO,YAAY,UAAU,QAAQ;;;;;AAMtC,SAAgB,wBACf,gBACA,SACC;AACD,2BAAa,OAAO,gBAAgB,QAAQ;;;;;AAM7C,SAAgB,uBAAuB,SAKpC;AACF,0BAAY,OAAO;EAClB,GAAG;EACH,YAAY,QAAQ,WAAW,aAAa;EAC5C,CAAC;;;;;;AAOH,SAAgB,2BACf,OACA,SAKC;AACD,8BAAW,OAAO,OAAO,QAAQ"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
3
2
|
|
|
4
3
|
//#region src/realtime/support-provider.d.ts
|
|
5
4
|
type SupportRealtimeProviderProps = {
|
|
@@ -11,7 +10,7 @@ type SupportRealtimeProviderProps = {
|
|
|
11
10
|
*/
|
|
12
11
|
declare function SupportRealtimeProvider({
|
|
13
12
|
children
|
|
14
|
-
}: SupportRealtimeProviderProps):
|
|
13
|
+
}: SupportRealtimeProviderProps): React.ReactElement;
|
|
15
14
|
//#endregion
|
|
16
15
|
export { SupportRealtimeProvider };
|
|
17
16
|
//# sourceMappingURL=support-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support-provider.d.ts","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"support-provider.d.ts","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":[],"mappings":";;;KAkBK,4BAAA;YACM,KAAA,CAAM;AAjBc,CAAA;AAwB/B;;;;AAEoD,iBAFpC,uBAAA,CAEoC;EAAA;AAAA,CAAA,EAAjD,4BAAiD,CAAA,EAAlB,KAAA,CAAM,YAAY"}
|
|
@@ -21,28 +21,27 @@ function SupportRealtimeProvider({ children }) {
|
|
|
21
21
|
visitor?.id,
|
|
22
22
|
client
|
|
23
23
|
]);
|
|
24
|
-
const events = useMemo(() => ({
|
|
25
|
-
timelineItemCreated: (_data, { event, context }) => {
|
|
26
|
-
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
27
|
-
clearTypingFromTimelineItem(event);
|
|
28
|
-
context.client.handleRealtimeEvent(event);
|
|
29
|
-
},
|
|
30
|
-
conversationSeen: (_data, { event, context }) => {
|
|
31
|
-
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
32
|
-
applyConversationSeenEvent(event);
|
|
33
|
-
},
|
|
34
|
-
conversationTyping: (_data, { event, context }) => {
|
|
35
|
-
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
36
|
-
applyConversationTypingEvent(event, { ignoreVisitorId: context.visitorId });
|
|
37
|
-
},
|
|
38
|
-
conversationEventCreated: (_data, { event, context }) => {
|
|
39
|
-
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
40
|
-
context.client.handleRealtimeEvent(event);
|
|
41
|
-
}
|
|
42
|
-
}), []);
|
|
43
24
|
useRealtime({
|
|
44
25
|
context: realtimeContext,
|
|
45
|
-
events
|
|
26
|
+
events: useMemo(() => ({
|
|
27
|
+
timelineItemCreated: (_data, { event, context }) => {
|
|
28
|
+
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
29
|
+
clearTypingFromTimelineItem(event);
|
|
30
|
+
context.client.handleRealtimeEvent(event);
|
|
31
|
+
},
|
|
32
|
+
conversationSeen: (_data, { event, context }) => {
|
|
33
|
+
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
34
|
+
applyConversationSeenEvent(event);
|
|
35
|
+
},
|
|
36
|
+
conversationTyping: (_data, { event, context }) => {
|
|
37
|
+
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
38
|
+
applyConversationTypingEvent(event, { ignoreVisitorId: context.visitorId });
|
|
39
|
+
},
|
|
40
|
+
conversationEventCreated: (_data, { event, context }) => {
|
|
41
|
+
if (context.websiteId && event.payload.websiteId !== context.websiteId) return;
|
|
42
|
+
context.client.handleRealtimeEvent(event);
|
|
43
|
+
}
|
|
44
|
+
}), []),
|
|
46
45
|
websiteId: realtimeContext.websiteId,
|
|
47
46
|
visitorId: realtimeContext.visitorId
|
|
48
47
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support-provider.js","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { applyConversationSeenEvent } from \"./seen-store\";\nimport {\n\tapplyConversationTypingEvent,\n\tclearTypingFromTimelineItem,\n} from \"./typing-store\";\nimport { useRealtime } from \"./use-realtime\";\n\ntype SupportRealtimeContext = {\n\twebsiteId: string | null;\n\tvisitorId: string | null;\n\tclient: CossistantClient;\n};\n\ntype SupportRealtimeProviderProps = {\n\tchildren: React.ReactNode;\n};\n\n/**\n * Bridges websocket events into the core client stores so support hooks stay\n * in sync without forcing refetches.\n */\nexport function SupportRealtimeProvider({\n\tchildren,\n}: SupportRealtimeProviderProps) {\n\tconst { website, client, visitor } = useSupport();\n\n\tconst realtimeContext = useMemo<SupportRealtimeContext>(\n\t\t() => ({\n\t\t\twebsiteId: website?.id ?? null,\n\t\t\tvisitorId: visitor?.id ?? null,\n\t\t\tclient,\n\t\t}),\n\t\t[website?.id, visitor?.id, client]\n\t);\n\n\tconst events = useMemo(\n\t\t() => ({\n\t\t\ttimelineItemCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"timelineItemCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Clear typing state when a timeline item is created\n\t\t\t\tclearTypingFromTimelineItem(event);\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t\tconversationSeen: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationSeen\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update the seen store so the UI reflects who has seen messages\n\t\t\t\tapplyConversationSeenEvent(event);\n\t\t\t},\n\t\t\tconversationTyping: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationTyping\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update typing store, but ignore events from the current visitor (their own typing)\n\t\t\t\t// Note: We use context.visitorId which is fresh from the context object\n\t\t\t\tapplyConversationTypingEvent(event, {\n\t\t\t\t\tignoreVisitorId: context.visitorId,\n\t\t\t\t});\n\t\t\t},\n\t\t\tconversationEventCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationEventCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t}),\n\t\t// Empty dependencies is fine here since we use the context parameter\n\t\t// which always has fresh data from the memoized realtimeContext\n\t\t[]\n\t);\n\n\tuseRealtime<SupportRealtimeContext>({\n\t\tcontext: realtimeContext,\n\t\tevents,\n\t\twebsiteId: realtimeContext.websiteId,\n\t\tvisitorId: realtimeContext.visitorId,\n\t});\n\n\treturn <>{children}</>;\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,wBAAwB,EACvC,
|
|
1
|
+
{"version":3,"file":"support-provider.js","names":[],"sources":["../../src/realtime/support-provider.tsx"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { applyConversationSeenEvent } from \"./seen-store\";\nimport {\n\tapplyConversationTypingEvent,\n\tclearTypingFromTimelineItem,\n} from \"./typing-store\";\nimport { useRealtime } from \"./use-realtime\";\n\ntype SupportRealtimeContext = {\n\twebsiteId: string | null;\n\tvisitorId: string | null;\n\tclient: CossistantClient;\n};\n\ntype SupportRealtimeProviderProps = {\n\tchildren: React.ReactNode;\n};\n\n/**\n * Bridges websocket events into the core client stores so support hooks stay\n * in sync without forcing refetches.\n */\nexport function SupportRealtimeProvider({\n\tchildren,\n}: SupportRealtimeProviderProps): React.ReactElement {\n\tconst { website, client, visitor } = useSupport();\n\n\tconst realtimeContext = useMemo<SupportRealtimeContext>(\n\t\t() => ({\n\t\t\twebsiteId: website?.id ?? null,\n\t\t\tvisitorId: visitor?.id ?? null,\n\t\t\tclient,\n\t\t}),\n\t\t[website?.id, visitor?.id, client]\n\t);\n\n\tconst events = useMemo(\n\t\t() => ({\n\t\t\ttimelineItemCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"timelineItemCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Clear typing state when a timeline item is created\n\t\t\t\tclearTypingFromTimelineItem(event);\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t\tconversationSeen: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationSeen\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update the seen store so the UI reflects who has seen messages\n\t\t\t\tapplyConversationSeenEvent(event);\n\t\t\t},\n\t\t\tconversationTyping: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationTyping\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Update typing store, but ignore events from the current visitor (their own typing)\n\t\t\t\t// Note: We use context.visitorId which is fresh from the context object\n\t\t\t\tapplyConversationTypingEvent(event, {\n\t\t\t\t\tignoreVisitorId: context.visitorId,\n\t\t\t\t});\n\t\t\t},\n\t\t\tconversationEventCreated: (\n\t\t\t\t_data: unknown,\n\t\t\t\t{\n\t\t\t\t\tevent,\n\t\t\t\t\tcontext,\n\t\t\t\t}: {\n\t\t\t\t\tevent: RealtimeEvent<\"conversationEventCreated\">;\n\t\t\t\t\tcontext: SupportRealtimeContext;\n\t\t\t\t}\n\t\t\t) => {\n\t\t\t\tif (\n\t\t\t\t\tcontext.websiteId &&\n\t\t\t\t\tevent.payload.websiteId !== context.websiteId\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontext.client.handleRealtimeEvent(event);\n\t\t\t},\n\t\t}),\n\t\t// Empty dependencies is fine here since we use the context parameter\n\t\t// which always has fresh data from the memoized realtimeContext\n\t\t[]\n\t);\n\n\tuseRealtime<SupportRealtimeContext>({\n\t\tcontext: realtimeContext,\n\t\tevents,\n\t\twebsiteId: realtimeContext.websiteId,\n\t\tvisitorId: realtimeContext.visitorId,\n\t});\n\n\treturn <>{children}</>;\n}\n"],"mappings":";;;;;;;;;;;;AA0BA,SAAgB,wBAAwB,EACvC,YACoD;CACpD,MAAM,EAAE,SAAS,QAAQ,YAAY,YAAY;CAEjD,MAAM,kBAAkB,eAChB;EACN,WAAW,SAAS,MAAM;EAC1B,WAAW,SAAS,MAAM;EAC1B;EACA,GACD;EAAC,SAAS;EAAI,SAAS;EAAI;EAAO,CAClC;AA8FD,aAAoC;EACnC,SAAS;EACT,QA9Fc,eACP;GACN,sBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAID,gCAA4B,MAAM;AAElC,YAAQ,OAAO,oBAAoB,MAAM;;GAE1C,mBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAID,+BAA2B,MAAM;;GAElC,qBACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAKD,iCAA6B,OAAO,EACnC,iBAAiB,QAAQ,WACzB,CAAC;;GAEH,2BACC,OACA,EACC,OACA,cAKG;AACJ,QACC,QAAQ,aACR,MAAM,QAAQ,cAAc,QAAQ,UAEpC;AAGD,YAAQ,OAAO,oBAAoB,MAAM;;GAE1C,GAGD,EAAE,CACF;EAKA,WAAW,gBAAgB;EAC3B,WAAW,gBAAgB;EAC3B,CAAC;AAEF,QAAO,gCAAG,WAAY"}
|
|
@@ -4,7 +4,14 @@ import { TypingActorType, TypingState } from "@cossistant/core";
|
|
|
4
4
|
//#region src/realtime/typing-store.d.ts
|
|
5
5
|
type Selector<T> = (state: TypingState) => T;
|
|
6
6
|
type EqualityChecker<T> = (previous: T, next: T) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Hook wrapper for the typing Zustand store used by realtime helpers.
|
|
9
|
+
*/
|
|
7
10
|
declare function useTypingStore<TSelected>(selector: Selector<TSelected>, isEqual?: EqualityChecker<TSelected>): TSelected;
|
|
11
|
+
/**
|
|
12
|
+
* Manually sets the typing state for a participant, typically in response to
|
|
13
|
+
* local input changes.
|
|
14
|
+
*/
|
|
8
15
|
declare function setTypingState(options: {
|
|
9
16
|
conversationId: string;
|
|
10
17
|
actorType: TypingActorType;
|
|
@@ -13,17 +20,28 @@ declare function setTypingState(options: {
|
|
|
13
20
|
preview?: string | null;
|
|
14
21
|
ttlMs?: number;
|
|
15
22
|
}): void;
|
|
23
|
+
/**
|
|
24
|
+
* Removes typing state entries for a participant.
|
|
25
|
+
*/
|
|
16
26
|
declare function clearTypingState(options: {
|
|
17
27
|
conversationId: string;
|
|
18
28
|
actorType: TypingActorType;
|
|
19
29
|
actorId: string;
|
|
20
30
|
}): void;
|
|
31
|
+
/**
|
|
32
|
+
* Applies realtime typing events to the store while supporting exclusions for
|
|
33
|
+
* the current visitor or agents.
|
|
34
|
+
*/
|
|
21
35
|
declare function applyConversationTypingEvent(event: RealtimeEvent<"conversationTyping">, options?: {
|
|
22
36
|
ignoreVisitorId?: string | null;
|
|
23
37
|
ignoreUserId?: string | null;
|
|
24
38
|
ignoreAiAgentId?: string | null;
|
|
25
39
|
ttlMs?: number;
|
|
26
40
|
}): void;
|
|
41
|
+
/**
|
|
42
|
+
* Utility invoked when a timeline item is created to clear stale typing
|
|
43
|
+
* indicators for the sender.
|
|
44
|
+
*/
|
|
27
45
|
declare function clearTypingFromTimelineItem(event: RealtimeEvent<"timelineItemCreated">): void;
|
|
28
46
|
//#endregion
|
|
29
47
|
export { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, setTypingState, useTypingStore };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typing-store.d.ts","names":[],"sources":["../../src/realtime/typing-store.ts"],"sourcesContent":[],"mappings":";;;;KAgBK,sBAAsB,gBAAgB;KAEtC,gCAAgC,SAAS;
|
|
1
|
+
{"version":3,"file":"typing-store.d.ts","names":[],"sources":["../../src/realtime/typing-store.ts"],"sourcesContent":[],"mappings":";;;;KAgBK,sBAAsB,gBAAgB;KAEtC,gCAAgC,SAAS;AAPyB;AAK3B;AAoC5C;AACoB,iBADJ,cACI,CAAA,SAAA,CAAA,CAAA,QAAA,EAAT,QAAS,CAAA,SAAA,CAAA,EAAA,OAAA,CAAA,EACT,eADS,CACO,SADP,CAAA,CAAA,EAEjB,SAFiB;;;;;AAER,iBAQI,cAAA,CARJ,OAAA,EAAA;EAQI,cAAA,EAAA,MAAc;EAcd,SAAA,EAZJ,eAYoB;EAYhB,OAAA,EAAA,MAAA;EAgBA,QAAA,EAAA,OAAA;;;;;;;iBA5BA,gBAAA;;aAEJ;;;;;;;iBAUI,4BAAA,QACR;;;;;;;;;;iBAeQ,2BAAA,QACR"}
|
package/realtime/typing-store.js
CHANGED
|
@@ -8,23 +8,40 @@ function useSelector(selector, isEqual = Object.is) {
|
|
|
8
8
|
const subscribe = (onStoreChange) => store.subscribe(() => {
|
|
9
9
|
onStoreChange();
|
|
10
10
|
});
|
|
11
|
-
const
|
|
12
|
-
const selected = selector(snapshot);
|
|
11
|
+
const selected = selector(useSyncExternalStore(subscribe, store.getState, store.getState));
|
|
13
12
|
if (selectionRef.current === void 0 || !isEqual(selectionRef.current, selected)) selectionRef.current = selected;
|
|
14
13
|
return selectionRef.current;
|
|
15
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Hook wrapper for the typing Zustand store used by realtime helpers.
|
|
17
|
+
*/
|
|
16
18
|
function useTypingStore(selector, isEqual) {
|
|
17
19
|
return useSelector(selector, isEqual);
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Manually sets the typing state for a participant, typically in response to
|
|
23
|
+
* local input changes.
|
|
24
|
+
*/
|
|
19
25
|
function setTypingState(options) {
|
|
20
26
|
setTypingState$1(store, options);
|
|
21
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Removes typing state entries for a participant.
|
|
30
|
+
*/
|
|
22
31
|
function clearTypingState(options) {
|
|
23
32
|
clearTypingState$1(store, options);
|
|
24
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Applies realtime typing events to the store while supporting exclusions for
|
|
36
|
+
* the current visitor or agents.
|
|
37
|
+
*/
|
|
25
38
|
function applyConversationTypingEvent(event, options) {
|
|
26
39
|
applyConversationTypingEvent$1(store, event, options);
|
|
27
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Utility invoked when a timeline item is created to clear stale typing
|
|
43
|
+
* indicators for the sender.
|
|
44
|
+
*/
|
|
28
45
|
function clearTypingFromTimelineItem(event) {
|
|
29
46
|
clearTypingFromTimelineItem$1(store, event);
|
|
30
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typing-store.js","names":[],"sources":["../../src/realtime/typing-store.ts"],"sourcesContent":["import {\n\tapplyConversationTypingEvent as applyEvent,\n\ttype ConversationTypingState,\n\tclearTypingFromTimelineItem as clearFromTimelineItem,\n\tclearTypingState as clearState,\n\tcreateTypingStore,\n\tsetTypingState as setState,\n\ttype TypingActorType,\n\ttype TypingEntry,\n\ttype TypingState,\n} from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport { useRef, useSyncExternalStore } from \"react\";\n\nconst store = createTypingStore();\n\ntype Selector<T> = (state: TypingState) => T;\n\ntype EqualityChecker<T> = (previous: T, next: T) => boolean;\n\nfunction useSelector<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual: EqualityChecker<TSelected> = Object.is\n): TSelected {\n\tconst selectionRef = useRef<TSelected>(undefined);\n\n\tconst subscribe = (onStoreChange: () => void) =>\n\t\tstore.subscribe(() => {\n\t\t\tonStoreChange();\n\t\t});\n\n\tconst snapshot = useSyncExternalStore(\n\t\tsubscribe,\n\t\tstore.getState,\n\t\tstore.getState\n\t);\n\n\tconst selected = selector(snapshot);\n\n\tif (\n\t\tselectionRef.current === undefined ||\n\t\t!isEqual(selectionRef.current, selected)\n\t) {\n\t\tselectionRef.current = selected;\n\t}\n\n\treturn selectionRef.current as TSelected;\n}\n\nexport function useTypingStore<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual?: EqualityChecker<TSelected>\n): TSelected {\n\treturn useSelector(selector, isEqual);\n}\n\nexport function setTypingState(options: {\n\tconversationId: string;\n\tactorType: TypingActorType;\n\tactorId: string;\n\tisTyping: boolean;\n\tpreview?: string | null;\n\tttlMs?: number;\n}) {\n\tsetState(store, options);\n}\n\nexport function clearTypingState(options: {\n\tconversationId: string;\n\tactorType: TypingActorType;\n\tactorId: string;\n}) {\n\tclearState(store, options);\n}\n\nexport function applyConversationTypingEvent(\n\tevent: RealtimeEvent<\"conversationTyping\">,\n\toptions?: {\n\t\tignoreVisitorId?: string | null;\n\t\tignoreUserId?: string | null;\n\t\tignoreAiAgentId?: string | null;\n\t\tttlMs?: number;\n\t}\n) {\n\tapplyEvent(store, event, options);\n}\n\nexport function clearTypingFromTimelineItem(\n\tevent: RealtimeEvent<\"timelineItemCreated\">\n) {\n\tclearFromTimelineItem(store, event);\n}\n"],"mappings":";;;;AAcA,MAAM,QAAQ,mBAAmB;AAMjC,SAAS,YACR,UACA,UAAsC,OAAO,IACjC;CACZ,MAAM,eAAe,OAAkB,OAAU;CAEjD,MAAM,aAAa,kBAClB,MAAM,gBAAgB;AACrB,iBAAe;GACd;
|
|
1
|
+
{"version":3,"file":"typing-store.js","names":[],"sources":["../../src/realtime/typing-store.ts"],"sourcesContent":["import {\n\tapplyConversationTypingEvent as applyEvent,\n\ttype ConversationTypingState,\n\tclearTypingFromTimelineItem as clearFromTimelineItem,\n\tclearTypingState as clearState,\n\tcreateTypingStore,\n\tsetTypingState as setState,\n\ttype TypingActorType,\n\ttype TypingEntry,\n\ttype TypingState,\n} from \"@cossistant/core\";\nimport type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport { useRef, useSyncExternalStore } from \"react\";\n\nconst store = createTypingStore();\n\ntype Selector<T> = (state: TypingState) => T;\n\ntype EqualityChecker<T> = (previous: T, next: T) => boolean;\n\nfunction useSelector<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual: EqualityChecker<TSelected> = Object.is\n): TSelected {\n\tconst selectionRef = useRef<TSelected>(undefined);\n\n\tconst subscribe = (onStoreChange: () => void) =>\n\t\tstore.subscribe(() => {\n\t\t\tonStoreChange();\n\t\t});\n\n\tconst snapshot = useSyncExternalStore(\n\t\tsubscribe,\n\t\tstore.getState,\n\t\tstore.getState\n\t);\n\n\tconst selected = selector(snapshot);\n\n\tif (\n\t\tselectionRef.current === undefined ||\n\t\t!isEqual(selectionRef.current, selected)\n\t) {\n\t\tselectionRef.current = selected;\n\t}\n\n\treturn selectionRef.current as TSelected;\n}\n\n/**\n * Hook wrapper for the typing Zustand store used by realtime helpers.\n */\nexport function useTypingStore<TSelected>(\n\tselector: Selector<TSelected>,\n\tisEqual?: EqualityChecker<TSelected>\n): TSelected {\n\treturn useSelector(selector, isEqual);\n}\n\n/**\n * Manually sets the typing state for a participant, typically in response to\n * local input changes.\n */\nexport function setTypingState(options: {\n\tconversationId: string;\n\tactorType: TypingActorType;\n\tactorId: string;\n\tisTyping: boolean;\n\tpreview?: string | null;\n\tttlMs?: number;\n}) {\n\tsetState(store, options);\n}\n\n/**\n * Removes typing state entries for a participant.\n */\nexport function clearTypingState(options: {\n\tconversationId: string;\n\tactorType: TypingActorType;\n\tactorId: string;\n}) {\n\tclearState(store, options);\n}\n\n/**\n * Applies realtime typing events to the store while supporting exclusions for\n * the current visitor or agents.\n */\nexport function applyConversationTypingEvent(\n\tevent: RealtimeEvent<\"conversationTyping\">,\n\toptions?: {\n\t\tignoreVisitorId?: string | null;\n\t\tignoreUserId?: string | null;\n\t\tignoreAiAgentId?: string | null;\n\t\tttlMs?: number;\n\t}\n) {\n\tapplyEvent(store, event, options);\n}\n\n/**\n * Utility invoked when a timeline item is created to clear stale typing\n * indicators for the sender.\n */\nexport function clearTypingFromTimelineItem(\n\tevent: RealtimeEvent<\"timelineItemCreated\">\n) {\n\tclearFromTimelineItem(store, event);\n}\n"],"mappings":";;;;AAcA,MAAM,QAAQ,mBAAmB;AAMjC,SAAS,YACR,UACA,UAAsC,OAAO,IACjC;CACZ,MAAM,eAAe,OAAkB,OAAU;CAEjD,MAAM,aAAa,kBAClB,MAAM,gBAAgB;AACrB,iBAAe;GACd;CAQH,MAAM,WAAW,SANA,qBAChB,WACA,MAAM,UACN,MAAM,SACN,CAEkC;AAEnC,KACC,aAAa,YAAY,UACzB,CAAC,QAAQ,aAAa,SAAS,SAAS,CAExC,cAAa,UAAU;AAGxB,QAAO,aAAa;;;;;AAMrB,SAAgB,eACf,UACA,SACY;AACZ,QAAO,YAAY,UAAU,QAAQ;;;;;;AAOtC,SAAgB,eAAe,SAO5B;AACF,kBAAS,OAAO,QAAQ;;;;;AAMzB,SAAgB,iBAAiB,SAI9B;AACF,oBAAW,OAAO,QAAQ;;;;;;AAO3B,SAAgB,6BACf,OACA,SAMC;AACD,gCAAW,OAAO,OAAO,QAAQ;;;;;;AAOlC,SAAgB,4BACf,OACC;AACD,+BAAsB,OAAO,MAAM"}
|
|
@@ -3,12 +3,12 @@ import { RealtimeContextValue } from "./provider.js";
|
|
|
3
3
|
|
|
4
4
|
//#region src/realtime/use-realtime.d.ts
|
|
5
5
|
type RealtimeHandlerContext<TContext> = TContext;
|
|
6
|
-
type RealtimeEventMeta<TType extends RealtimeEventType, TContext> = {
|
|
7
|
-
event: RealtimeEvent<TType>;
|
|
6
|
+
type RealtimeEventMeta<TType$1 extends RealtimeEventType, TContext> = {
|
|
7
|
+
event: RealtimeEvent<TType$1>;
|
|
8
8
|
context: RealtimeHandlerContext<TContext>;
|
|
9
9
|
};
|
|
10
|
-
type RealtimeEventHandler<TType extends RealtimeEventType, TContext> = (data: RealtimeEventData<TType>, meta: RealtimeEventMeta<TType, TContext>) => void | Promise<void>;
|
|
11
|
-
type RealtimeEventHandlerEntry<TType extends RealtimeEventType, TContext> = RealtimeEventHandler<TType, TContext> | RealtimeEventHandler<TType, TContext>[];
|
|
10
|
+
type RealtimeEventHandler<TType$1 extends RealtimeEventType, TContext> = (data: RealtimeEventData<TType$1>, meta: RealtimeEventMeta<TType$1, TContext>) => void | Promise<void>;
|
|
11
|
+
type RealtimeEventHandlerEntry<TType$1 extends RealtimeEventType, TContext> = RealtimeEventHandler<TType$1, TContext> | RealtimeEventHandler<TType$1, TContext>[];
|
|
12
12
|
type RealtimeEventHandlersMap<TContext> = Partial<{ [TType in RealtimeEventType]: RealtimeEventHandlerEntry<TType, TContext> }>;
|
|
13
13
|
type UseRealtimeOptions<TContext, THandlers extends RealtimeEventHandlersMap<TContext>> = {
|
|
14
14
|
events: THandlers;
|
|
@@ -17,6 +17,10 @@ type UseRealtimeOptions<TContext, THandlers extends RealtimeEventHandlersMap<TCo
|
|
|
17
17
|
context?: TContext;
|
|
18
18
|
onEventError?: (error: unknown, event: RealtimeEvent<RealtimeEventType>) => void;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Binds realtime connection events to typed handler maps with automatic
|
|
22
|
+
* filtering by website/visitor ids.
|
|
23
|
+
*/
|
|
20
24
|
declare function useRealtime<TContext = void, THandlers extends RealtimeEventHandlersMap<TContext> = RealtimeEventHandlersMap<TContext>>({
|
|
21
25
|
events,
|
|
22
26
|
websiteId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-realtime.d.ts","names":[],"sources":["../../src/realtime/use-realtime.ts"],"sourcesContent":[],"mappings":";;;;KAUY,mCAAmC;KAEnC,
|
|
1
|
+
{"version":3,"file":"use-realtime.d.ts","names":[],"sources":["../../src/realtime/use-realtime.ts"],"sourcesContent":[],"mappings":";;;;KAUY,mCAAmC;KAEnC,kCAAgC;SACpC,cAAc;EAHV,OAAA,EAIF,sBAJwB,CAID,QAJC,CAAA;AAElC,CAAA;AAA4C,KAKhC,oBALgC,CAAA,gBAKG,iBALH,EAAA,QAAA,CAAA,GAAA,CAAA,IAAA,EAMrC,iBANqC,CAMnB,OANmB,CAAA,EAAA,IAAA,EAOrC,iBAPqC,CAOnB,OAPmB,EAOZ,QAPY,CAAA,EAAA,GAAA,IAAA,GAQhC,OARgC,CAAA,IAAA,CAAA;AACtB,KASV,yBATU,CAAA,gBAUP,iBAVO,EAAA,QAAA,CAAA,GAanB,oBAbmB,CAaE,OAbF,EAaS,QAbT,CAAA,GAcnB,oBAdmB,CAcE,OAdF,EAcS,QAdT,CAAA,EAAA;AAAd,KAgBI,wBAhBJ,CAAA,QAAA,CAAA,GAgByC,OAhBzC,CAAA,YAiBG,iBAhBsB,GAgBF,yBAhBE,CAgBwB,KAhBxB,EAgB+B,QAhB/B,CAAA,EAAvB,CAAA;KAmBL,kBAnB2B,CAAA,QAAA,EAAA,kBAqBb,wBArBa,CAqBY,QArBZ,CAAA,CAAA,GAAA;EAGpB,MAAA,EAoBH,SApBG;EAAmC,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EACtB,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAlB,OAAA,CAAA,EAsBI,QAtBJ;EACkB,YAAA,CAAA,EAAA,CAAA,KAAA,EAAA,OAAA,EAAA,KAAA,EAwBhB,aAxBgB,CAwBF,iBAxBE,CAAA,EAAA,GAAA,IAAA;CAAO;;;;AAGhC;AACe,iBA4BC,WA5BD,CAAA,WAAA,IAAA,EAAA,kBA+Bb,wBA/Ba,CA+BY,QA/BZ,CAAA,GA+BwB,wBA/BxB,CA+BiD,QA/BjD,CAAA,CAAA,CAAA;EAAA,MAAA;EAAA,SAAA;EAAA,SAAA;EAAA,OAAA;EAAA;AAAA,CAAA,EAsCZ,kBAtCY,CAsCO,QAtCP,EAsCiB,SAtCjB,CAAA,CAAA,EAsCM,oBAtCN"}
|
package/realtime/use-realtime.js
CHANGED
|
@@ -3,6 +3,10 @@ import { shouldDeliverEvent } from "./event-filter.js";
|
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/realtime/use-realtime.ts
|
|
6
|
+
/**
|
|
7
|
+
* Binds realtime connection events to typed handler maps with automatic
|
|
8
|
+
* filtering by website/visitor ids.
|
|
9
|
+
*/
|
|
6
10
|
function useRealtime({ events, websiteId, visitorId, context, onEventError }) {
|
|
7
11
|
const connection = useRealtimeConnection();
|
|
8
12
|
const handlersRef = useRef(events);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-realtime.js","names":[],"sources":["../../src/realtime/use-realtime.ts"],"sourcesContent":["import type {\n\tAnyRealtimeEvent,\n\tRealtimeEvent,\n\tRealtimeEventData,\n\tRealtimeEventType,\n} from \"@cossistant/types/realtime-events\";\nimport { useEffect, useRef } from \"react\";\nimport { shouldDeliverEvent } from \"./event-filter\";\nimport { useRealtimeConnection } from \"./provider\";\n\nexport type RealtimeHandlerContext<TContext> = TContext;\n\nexport type RealtimeEventMeta<TType extends RealtimeEventType, TContext> = {\n\tevent: RealtimeEvent<TType>;\n\tcontext: RealtimeHandlerContext<TContext>;\n};\n\nexport type RealtimeEventHandler<TType extends RealtimeEventType, TContext> = (\n\tdata: RealtimeEventData<TType>,\n\tmeta: RealtimeEventMeta<TType, TContext>\n) => void | Promise<void>;\n\nexport type RealtimeEventHandlerEntry<\n\tTType extends RealtimeEventType,\n\tTContext,\n> =\n\t| RealtimeEventHandler<TType, TContext>\n\t| RealtimeEventHandler<TType, TContext>[];\n\nexport type RealtimeEventHandlersMap<TContext> = Partial<{\n\t[TType in RealtimeEventType]: RealtimeEventHandlerEntry<TType, TContext>;\n}>;\n\ntype UseRealtimeOptions<\n\tTContext,\n\tTHandlers extends RealtimeEventHandlersMap<TContext>,\n> = {\n\tevents: THandlers;\n\twebsiteId?: string | null;\n\tvisitorId?: string | null;\n\tcontext?: TContext;\n\tonEventError?: (\n\t\terror: unknown,\n\t\tevent: RealtimeEvent<RealtimeEventType>\n\t) => void;\n};\n\nexport function useRealtime<\n\tTContext = void,\n\tTHandlers extends\n\t\tRealtimeEventHandlersMap<TContext> = RealtimeEventHandlersMap<TContext>,\n>({\n\tevents,\n\twebsiteId,\n\tvisitorId,\n\tcontext,\n\tonEventError,\n}: UseRealtimeOptions<TContext, THandlers>) {\n\tconst connection = useRealtimeConnection();\n\tconst handlersRef = useRef<RealtimeEventHandlersMap<TContext>>(events);\n\tconst contextRef = useRef<TContext | undefined>(context);\n\tconst websiteIdRef = useRef<string | null>(websiteId ?? null);\n\tconst visitorIdRef = useRef<string | null>(visitorId ?? null);\n\tconst errorHandlerRef = useRef<\n\t\t| ((error: unknown, event: RealtimeEvent<RealtimeEventType>) => void)\n\t\t| undefined\n\t>(onEventError);\n\n\tuseEffect(() => {\n\t\thandlersRef.current = events;\n\t}, [events]);\n\n\tuseEffect(() => {\n\t\tcontextRef.current = context;\n\t}, [context]);\n\n\tuseEffect(() => {\n\t\twebsiteIdRef.current = websiteId ?? null;\n\t}, [websiteId]);\n\n\tuseEffect(() => {\n\t\tvisitorIdRef.current = visitorId ?? null;\n\t}, [visitorId]);\n\n\tuseEffect(() => {\n\t\terrorHandlerRef.current = onEventError;\n\t}, [onEventError]);\n\n\tuseEffect(\n\t\t() =>\n\t\t\tconnection.subscribe((event) => {\n\t\t\t\tconst handlers = handlersRef.current[event.type];\n\n\t\t\t\tif (!handlers) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!shouldDeliverEvent(event, websiteIdRef.current, visitorIdRef.current)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst payload = Array.isArray(handlers) ? handlers : [handlers];\n\n\t\t\t\tfor (const handler of payload) {\n\t\t\t\t\tPromise.resolve(\n\t\t\t\t\t\thandler(event.payload as never, {\n\t\t\t\t\t\t\tevent: event as never,\n\t\t\t\t\t\t\tcontext: contextRef.current as TContext,\n\t\t\t\t\t\t})\n\t\t\t\t\t).catch((error) => {\n\t\t\t\t\t\tconst errorHandler = errorHandlerRef.current;\n\t\t\t\t\t\tif (errorHandler) {\n\t\t\t\t\t\t\terrorHandler(error, event);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error(\"[Realtime] Event handler threw an error\", error);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t\t[connection]\n\t);\n\n\treturn connection;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-realtime.js","names":[],"sources":["../../src/realtime/use-realtime.ts"],"sourcesContent":["import type {\n\tAnyRealtimeEvent,\n\tRealtimeEvent,\n\tRealtimeEventData,\n\tRealtimeEventType,\n} from \"@cossistant/types/realtime-events\";\nimport { useEffect, useRef } from \"react\";\nimport { shouldDeliverEvent } from \"./event-filter\";\nimport { useRealtimeConnection } from \"./provider\";\n\nexport type RealtimeHandlerContext<TContext> = TContext;\n\nexport type RealtimeEventMeta<TType extends RealtimeEventType, TContext> = {\n\tevent: RealtimeEvent<TType>;\n\tcontext: RealtimeHandlerContext<TContext>;\n};\n\nexport type RealtimeEventHandler<TType extends RealtimeEventType, TContext> = (\n\tdata: RealtimeEventData<TType>,\n\tmeta: RealtimeEventMeta<TType, TContext>\n) => void | Promise<void>;\n\nexport type RealtimeEventHandlerEntry<\n\tTType extends RealtimeEventType,\n\tTContext,\n> =\n\t| RealtimeEventHandler<TType, TContext>\n\t| RealtimeEventHandler<TType, TContext>[];\n\nexport type RealtimeEventHandlersMap<TContext> = Partial<{\n\t[TType in RealtimeEventType]: RealtimeEventHandlerEntry<TType, TContext>;\n}>;\n\ntype UseRealtimeOptions<\n\tTContext,\n\tTHandlers extends RealtimeEventHandlersMap<TContext>,\n> = {\n\tevents: THandlers;\n\twebsiteId?: string | null;\n\tvisitorId?: string | null;\n\tcontext?: TContext;\n\tonEventError?: (\n\t\terror: unknown,\n\t\tevent: RealtimeEvent<RealtimeEventType>\n\t) => void;\n};\n\n/**\n * Binds realtime connection events to typed handler maps with automatic\n * filtering by website/visitor ids.\n */\nexport function useRealtime<\n\tTContext = void,\n\tTHandlers extends\n\t\tRealtimeEventHandlersMap<TContext> = RealtimeEventHandlersMap<TContext>,\n>({\n\tevents,\n\twebsiteId,\n\tvisitorId,\n\tcontext,\n\tonEventError,\n}: UseRealtimeOptions<TContext, THandlers>) {\n\tconst connection = useRealtimeConnection();\n\tconst handlersRef = useRef<RealtimeEventHandlersMap<TContext>>(events);\n\tconst contextRef = useRef<TContext | undefined>(context);\n\tconst websiteIdRef = useRef<string | null>(websiteId ?? null);\n\tconst visitorIdRef = useRef<string | null>(visitorId ?? null);\n\tconst errorHandlerRef = useRef<\n\t\t| ((error: unknown, event: RealtimeEvent<RealtimeEventType>) => void)\n\t\t| undefined\n\t>(onEventError);\n\n\tuseEffect(() => {\n\t\thandlersRef.current = events;\n\t}, [events]);\n\n\tuseEffect(() => {\n\t\tcontextRef.current = context;\n\t}, [context]);\n\n\tuseEffect(() => {\n\t\twebsiteIdRef.current = websiteId ?? null;\n\t}, [websiteId]);\n\n\tuseEffect(() => {\n\t\tvisitorIdRef.current = visitorId ?? null;\n\t}, [visitorId]);\n\n\tuseEffect(() => {\n\t\terrorHandlerRef.current = onEventError;\n\t}, [onEventError]);\n\n\tuseEffect(\n\t\t() =>\n\t\t\tconnection.subscribe((event) => {\n\t\t\t\tconst handlers = handlersRef.current[event.type];\n\n\t\t\t\tif (!handlers) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!shouldDeliverEvent(event, websiteIdRef.current, visitorIdRef.current)\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst payload = Array.isArray(handlers) ? handlers : [handlers];\n\n\t\t\t\tfor (const handler of payload) {\n\t\t\t\t\tPromise.resolve(\n\t\t\t\t\t\thandler(event.payload as never, {\n\t\t\t\t\t\t\tevent: event as never,\n\t\t\t\t\t\t\tcontext: contextRef.current as TContext,\n\t\t\t\t\t\t})\n\t\t\t\t\t).catch((error) => {\n\t\t\t\t\t\tconst errorHandler = errorHandlerRef.current;\n\t\t\t\t\t\tif (errorHandler) {\n\t\t\t\t\t\t\terrorHandler(error, event);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconsole.error(\"[Realtime] Event handler threw an error\", error);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}),\n\t\t[connection]\n\t);\n\n\treturn connection;\n}\n"],"mappings":";;;;;;;;;AAmDA,SAAgB,YAId,EACD,QACA,WACA,WACA,SACA,gBAC2C;CAC3C,MAAM,aAAa,uBAAuB;CAC1C,MAAM,cAAc,OAA2C,OAAO;CACtE,MAAM,aAAa,OAA6B,QAAQ;CACxD,MAAM,eAAe,OAAsB,aAAa,KAAK;CAC7D,MAAM,eAAe,OAAsB,aAAa,KAAK;CAC7D,MAAM,kBAAkB,OAGtB,aAAa;AAEf,iBAAgB;AACf,cAAY,UAAU;IACpB,CAAC,OAAO,CAAC;AAEZ,iBAAgB;AACf,aAAW,UAAU;IACnB,CAAC,QAAQ,CAAC;AAEb,iBAAgB;AACf,eAAa,UAAU,aAAa;IAClC,CAAC,UAAU,CAAC;AAEf,iBAAgB;AACf,eAAa,UAAU,aAAa;IAClC,CAAC,UAAU,CAAC;AAEf,iBAAgB;AACf,kBAAgB,UAAU;IACxB,CAAC,aAAa,CAAC;AAElB,iBAEE,WAAW,WAAW,UAAU;EAC/B,MAAM,WAAW,YAAY,QAAQ,MAAM;AAE3C,MAAI,CAAC,SACJ;AAGD,MACC,CAAC,mBAAmB,OAAO,aAAa,SAAS,aAAa,QAAQ,CAEtE;EAGD,MAAM,UAAU,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS;AAE/D,OAAK,MAAM,WAAW,QACrB,SAAQ,QACP,QAAQ,MAAM,SAAkB;GACxB;GACP,SAAS,WAAW;GACpB,CAAC,CACF,CAAC,OAAO,UAAU;GAClB,MAAM,eAAe,gBAAgB;AACrC,OAAI,aACH,cAAa,OAAO,MAAM;OAE1B,SAAQ,MAAM,2CAA2C,MAAM;IAE/D;GAEF,EACH,CAAC,WAAW,CACZ;AAED,QAAO"}
|
package/realtime-events.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ declare const realtimeSchema: {
|
|
|
83
83
|
type: z.ZodEnum<{
|
|
84
84
|
message: "message";
|
|
85
85
|
event: "event";
|
|
86
|
+
identification: "identification";
|
|
86
87
|
}>;
|
|
87
88
|
text: z.ZodNullable<z.ZodString>;
|
|
88
89
|
parts: z.ZodArray<z.ZodUnknown>;
|
|
@@ -91,6 +92,7 @@ declare const realtimeSchema: {
|
|
|
91
92
|
aiAgentId: z.ZodNullable<z.ZodString>;
|
|
92
93
|
createdAt: z.ZodString;
|
|
93
94
|
deletedAt: z.ZodNullable<z.ZodString>;
|
|
95
|
+
tool: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
94
96
|
}, z.core.$strip>;
|
|
95
97
|
}, z.core.$strip>;
|
|
96
98
|
readonly conversationCreated: z.ZodObject<{
|
|
@@ -107,10 +109,11 @@ declare const realtimeSchema: {
|
|
|
107
109
|
visitorId: z.ZodString;
|
|
108
110
|
websiteId: z.ZodString;
|
|
109
111
|
status: z.ZodDefault<z.ZodEnum<{
|
|
110
|
-
resolved: "resolved";
|
|
111
112
|
open: "open";
|
|
113
|
+
resolved: "resolved";
|
|
112
114
|
spam: "spam";
|
|
113
115
|
}>>;
|
|
116
|
+
deletedAt: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
114
117
|
lastTimelineItem: z.ZodOptional<z.ZodObject<{
|
|
115
118
|
id: z.ZodOptional<z.ZodString>;
|
|
116
119
|
conversationId: z.ZodString;
|
|
@@ -122,8 +125,10 @@ declare const realtimeSchema: {
|
|
|
122
125
|
type: z.ZodEnum<{
|
|
123
126
|
message: "message";
|
|
124
127
|
event: "event";
|
|
128
|
+
identification: "identification";
|
|
125
129
|
}>;
|
|
126
130
|
text: z.ZodNullable<z.ZodString>;
|
|
131
|
+
tool: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
127
132
|
parts: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
128
133
|
type: z.ZodLiteral<"text">;
|
|
129
134
|
text: z.ZodString;
|
|
@@ -141,6 +146,9 @@ declare const realtimeSchema: {
|
|
|
141
146
|
tag_removed: "tag_removed";
|
|
142
147
|
resolved: "resolved";
|
|
143
148
|
reopened: "reopened";
|
|
149
|
+
visitor_blocked: "visitor_blocked";
|
|
150
|
+
visitor_unblocked: "visitor_unblocked";
|
|
151
|
+
visitor_identified: "visitor_identified";
|
|
144
152
|
}>;
|
|
145
153
|
actorUserId: z.ZodNullable<z.ZodString>;
|
|
146
154
|
actorAiAgentId: z.ZodNullable<z.ZodString>;
|
|
@@ -172,14 +180,14 @@ declare const realtimeSchema: {
|
|
|
172
180
|
header: z.ZodObject<{
|
|
173
181
|
id: z.ZodString;
|
|
174
182
|
status: z.ZodEnum<{
|
|
175
|
-
resolved: "resolved";
|
|
176
183
|
open: "open";
|
|
184
|
+
resolved: "resolved";
|
|
177
185
|
spam: "spam";
|
|
178
186
|
}>;
|
|
179
187
|
priority: z.ZodEnum<{
|
|
180
|
-
normal: "normal";
|
|
181
188
|
high: "high";
|
|
182
189
|
low: "low";
|
|
190
|
+
normal: "normal";
|
|
183
191
|
urgent: "urgent";
|
|
184
192
|
}>;
|
|
185
193
|
organizationId: z.ZodString;
|
|
@@ -195,6 +203,7 @@ declare const realtimeSchema: {
|
|
|
195
203
|
name: z.ZodNullable<z.ZodString>;
|
|
196
204
|
email: z.ZodNullable<z.ZodString>;
|
|
197
205
|
image: z.ZodNullable<z.ZodString>;
|
|
206
|
+
metadataHash: z.ZodOptional<z.ZodString>;
|
|
198
207
|
}, z.core.$strip>>;
|
|
199
208
|
}, z.core.$strip>;
|
|
200
209
|
websiteId: z.ZodString;
|
|
@@ -222,8 +231,10 @@ declare const realtimeSchema: {
|
|
|
222
231
|
type: z.ZodEnum<{
|
|
223
232
|
message: "message";
|
|
224
233
|
event: "event";
|
|
234
|
+
identification: "identification";
|
|
225
235
|
}>;
|
|
226
236
|
text: z.ZodNullable<z.ZodString>;
|
|
237
|
+
tool: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
227
238
|
parts: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
228
239
|
type: z.ZodLiteral<"text">;
|
|
229
240
|
text: z.ZodString;
|
|
@@ -241,6 +252,9 @@ declare const realtimeSchema: {
|
|
|
241
252
|
tag_removed: "tag_removed";
|
|
242
253
|
resolved: "resolved";
|
|
243
254
|
reopened: "reopened";
|
|
255
|
+
visitor_blocked: "visitor_blocked";
|
|
256
|
+
visitor_unblocked: "visitor_unblocked";
|
|
257
|
+
visitor_identified: "visitor_identified";
|
|
244
258
|
}>;
|
|
245
259
|
actorUserId: z.ZodNullable<z.ZodString>;
|
|
246
260
|
actorAiAgentId: z.ZodNullable<z.ZodString>;
|
package/realtime-events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"realtime-events.d.ts","names":[],"sources":["../../types/src/realtime-events.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAiBa
|
|
1
|
+
{"version":3,"file":"realtime-events.d.ts","names":[],"sources":["../../types/src/realtime-events.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAiBa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmED,iBAAA,gBAAiC;KAEjC,+BAA+B,qBAAqB,CAAA,CAAE,cACzD,gBAAgB;KAGb,wBAAwB;QAC7B;WACG,qBAAqB;;KAGnB,gBAAA,WACL,oBAAoB,cAAc,KACvC;KAEU,4BAA4B,qBACvC,qBAAqB"}
|
package/schemas.d.ts
CHANGED
|
@@ -10,10 +10,11 @@ declare const conversationSchema: z.ZodObject<{
|
|
|
10
10
|
visitorId: z.ZodString;
|
|
11
11
|
websiteId: z.ZodString;
|
|
12
12
|
status: z.ZodDefault<z.ZodEnum<{
|
|
13
|
-
resolved: "resolved";
|
|
14
13
|
open: "open";
|
|
14
|
+
resolved: "resolved";
|
|
15
15
|
spam: "spam";
|
|
16
16
|
}>>;
|
|
17
|
+
deletedAt: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
17
18
|
lastTimelineItem: z.ZodOptional<z.ZodObject<{
|
|
18
19
|
id: z.ZodOptional<z.ZodString>;
|
|
19
20
|
conversationId: z.ZodString;
|
|
@@ -25,8 +26,10 @@ declare const conversationSchema: z.ZodObject<{
|
|
|
25
26
|
type: z.ZodEnum<{
|
|
26
27
|
message: "message";
|
|
27
28
|
event: "event";
|
|
29
|
+
identification: "identification";
|
|
28
30
|
}>;
|
|
29
31
|
text: z.ZodNullable<z.ZodString>;
|
|
32
|
+
tool: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
30
33
|
parts: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
31
34
|
type: z.ZodLiteral<"text">;
|
|
32
35
|
text: z.ZodString;
|
|
@@ -44,6 +47,9 @@ declare const conversationSchema: z.ZodObject<{
|
|
|
44
47
|
tag_removed: "tag_removed";
|
|
45
48
|
resolved: "resolved";
|
|
46
49
|
reopened: "reopened";
|
|
50
|
+
visitor_blocked: "visitor_blocked";
|
|
51
|
+
visitor_unblocked: "visitor_unblocked";
|
|
52
|
+
visitor_identified: "visitor_identified";
|
|
47
53
|
}>;
|
|
48
54
|
actorUserId: z.ZodNullable<z.ZodString>;
|
|
49
55
|
actorAiAgentId: z.ZodNullable<z.ZodString>;
|
package/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","names":[],"sources":["../../types/src/schemas.ts"],"sourcesContent":[],"mappings":";;;;cAkBa,oBAAkB,CAAA,CAAA
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","names":[],"sources":["../../types/src/schemas.ts"],"sourcesContent":[],"mappings":";;;;cAkBa,oBAAkB,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAA,SAAA,eAAA,YAAA,CAAA;IAAA,SAAA,aAAA;IAkBnB,SAAA,eAA8B,cAAA,YAAb,CAAA,CAAK;EAErB,CAAA,eAAA,CAAA,CAAA;;KAFD,YAAA,GAAe,CAAA,CAAE,aAAa;cAE7B,wBAAsB,CAAA,CAAA;;;;;;;;;;;KAYvB,gBAAA,GAAmB,CAAA,CAAE,aAAa"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactElement, ReactNode } from "react";
|
|
2
2
|
import { AvailableAIAgent, AvailableHumanAgent } from "@cossistant/types";
|
|
3
3
|
|
|
4
4
|
//#region src/support/components/avatar-stack.d.ts
|
|
@@ -23,13 +23,17 @@ declare const AvatarStackItem: ({
|
|
|
23
23
|
gapWidth,
|
|
24
24
|
className
|
|
25
25
|
}: {
|
|
26
|
-
children:
|
|
26
|
+
children: ReactNode;
|
|
27
27
|
index: number;
|
|
28
28
|
size?: number;
|
|
29
29
|
spacing?: number;
|
|
30
30
|
gapWidth?: number;
|
|
31
31
|
className?: string;
|
|
32
|
-
}) =>
|
|
32
|
+
}) => ReactElement | null;
|
|
33
|
+
/**
|
|
34
|
+
* Displays a compact row of agent avatars with optional branding and overflow
|
|
35
|
+
* counts.
|
|
36
|
+
*/
|
|
33
37
|
declare function AvatarStack({
|
|
34
38
|
humanAgents,
|
|
35
39
|
aiAgents,
|
|
@@ -39,7 +43,7 @@ declare function AvatarStack({
|
|
|
39
43
|
size,
|
|
40
44
|
spacing,
|
|
41
45
|
gapWidth
|
|
42
|
-
}: AvatarStackProps):
|
|
46
|
+
}: AvatarStackProps): ReactElement | null;
|
|
43
47
|
//#endregion
|
|
44
48
|
export { AvatarStack, AvatarStackItem };
|
|
45
49
|
//# sourceMappingURL=avatar-stack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar-stack.d.ts","names":[],"sources":["../../../src/support/components/avatar-stack.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"avatar-stack.d.ts","names":[],"sources":["../../../src/support/components/avatar-stack.tsx"],"sourcesContent":[],"mappings":";;;;KAOK,gBAAA;eACS;EADT,QAAA,EAEM,gBAFU,EAAA;EAcR,YAAA,CAAA,EAAA,OA8CZ;EA9C+B,kBAAA,CAAA,EAAA,OAAA;EAAA,SAAA,CAAA,EAAA,MAAA;EAAA;EAAA,IAAA,CAAA,EAAA,MAAA;EAAA;EAAA,OAAA,CAAA,EAAA,MAAA;EAQrB;EAMP,QAAA,CAAA,EAAA,MAAA;CAAY;AAsCA,cApDH,eAoDc,EAAA,CAAA;EAAA,QAAA;EAAA,KAAA;EAAA,IAAA;EAAA,OAAA;EAAA,QAAA;EAAA;CAAA,EAAA;EAC1B,QAAA,EA7CU,SA6CV;EACA,KAAA,EAAA,MAAA;EACA,IAAA,CAAA,EAAA,MAAA;EACA,OAAA,CAAA,EAAA,MAAA;EACA,QAAA,CAAA,EAAA,MAAA;EACA,SAAA,CAAA,EAAA,MAAA;CACA,EAAA,GA7CG,YA6CH,GAAA,IAAA;;;;;iBAPe,WAAA;;;;;;;;;GASb,mBAAmB"}
|
|
@@ -23,6 +23,10 @@ const AvatarStackItem = ({ children, index, size = 44, spacing = 28, gapWidth =
|
|
|
23
23
|
children
|
|
24
24
|
} });
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Displays a compact row of agent avatars with optional branding and overflow
|
|
28
|
+
* counts.
|
|
29
|
+
*/
|
|
26
30
|
function AvatarStack({ humanAgents, aiAgents, hideBranding = false, hideDefaultAIAgent = true, className, size = 44, spacing = 28, gapWidth = 3 }) {
|
|
27
31
|
const displayedHumanAgents = humanAgents.slice(0, 2);
|
|
28
32
|
const remainingHumanAgentsCount = Math.max(0, humanAgents.length - 2);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar-stack.js","names":[],"sources":["../../../src/support/components/avatar-stack.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport { useRenderElement } from \"../../utils/use-render-element\";\nimport { cn } from \"../utils\";\nimport { Avatar } from \"./avatar\";\nimport { CossistantLogo } from \"./cossistant-branding\";\n\ntype AvatarStackProps = {\n\thumanAgents: AvailableHumanAgent[];\n\taiAgents: AvailableAIAgent[];\n\thideBranding?: boolean;\n\thideDefaultAIAgent?: boolean;\n\tclassName?: string;\n\t/** Size of avatars (default: 44px) */\n\tsize?: number;\n\t/** Space between avatars (default: 28px) */\n\tspacing?: number;\n\t/** Gap width between avatars (default: 2px) */\n\tgapWidth?: number;\n};\n\nexport const AvatarStackItem = ({\n\tchildren,\n\tindex,\n\tsize = 44,\n\tspacing = 28,\n\tgapWidth = 2,\n\tclassName,\n}: {\n\tchildren:
|
|
1
|
+
{"version":3,"file":"avatar-stack.js","names":[],"sources":["../../../src/support/components/avatar-stack.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { useRenderElement } from \"../../utils/use-render-element\";\nimport { cn } from \"../utils\";\nimport { Avatar } from \"./avatar\";\nimport { CossistantLogo } from \"./cossistant-branding\";\n\ntype AvatarStackProps = {\n\thumanAgents: AvailableHumanAgent[];\n\taiAgents: AvailableAIAgent[];\n\thideBranding?: boolean;\n\thideDefaultAIAgent?: boolean;\n\tclassName?: string;\n\t/** Size of avatars (default: 44px) */\n\tsize?: number;\n\t/** Space between avatars (default: 28px) */\n\tspacing?: number;\n\t/** Gap width between avatars (default: 2px) */\n\tgapWidth?: number;\n};\n\nexport const AvatarStackItem = ({\n\tchildren,\n\tindex,\n\tsize = 44,\n\tspacing = 28,\n\tgapWidth = 2,\n\tclassName,\n}: {\n\tchildren: ReactNode;\n\tindex: number;\n\tsize?: number;\n\tspacing?: number;\n\tgapWidth?: number;\n\tclassName?: string;\n}): ReactElement | null => {\n\tconst isFirst = index === 0;\n\n\t// Calculate the circle radius for the mask cutout\n\tconst circleRadius = size * 0.5;\n\tconst cutoutRadius = circleRadius + gapWidth; // Add gap width to create visible border\n\tconst cutoutPosition = `${circleRadius - spacing}px`;\n\n\treturn useRenderElement(\n\t\t\"div\",\n\t\t{ className },\n\t\t{\n\t\t\tprops: {\n\t\t\t\tclassName: cn(\n\t\t\t\t\t\"relative grid place-items-center\",\n\t\t\t\t\t!isFirst && \"[mask-repeat:no-repeat] [mask-size:100%_100%]\"\n\t\t\t\t),\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: `${size}px`,\n\t\t\t\t\theight: `${size}px`,\n\t\t\t\t\t// Apply mask only to non-first items\n\t\t\t\t\t...(isFirst\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tmask: `radial-gradient(${cutoutRadius}px ${cutoutRadius}px at ${cutoutPosition} 50%, transparent ${cutoutRadius}px, white ${cutoutRadius}px)`,\n\t\t\t\t\t\t\t\tWebkitMask: `radial-gradient(${cutoutRadius}px ${cutoutRadius}px at ${cutoutPosition} 50%, transparent ${cutoutRadius}px, white ${cutoutRadius}px)`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tchildren,\n\t\t\t},\n\t\t}\n\t);\n};\n\n/**\n * Displays a compact row of agent avatars with optional branding and overflow\n * counts.\n */\nexport function AvatarStack({\n\thumanAgents,\n\taiAgents,\n\thideBranding = false,\n\thideDefaultAIAgent = true,\n\tclassName,\n\tsize = 44,\n\tspacing = 28,\n\tgapWidth = 3,\n}: AvatarStackProps): ReactElement | null {\n\tconst displayedHumanAgents = humanAgents.slice(0, 2);\n\tconst remainingHumanAgentsCount = Math.max(0, humanAgents.length - 2);\n\n\t// Create array of all items to display\n\tconst items = [\n\t\t...displayedHumanAgents.map((agent) => ({\n\t\t\ttype: \"human\" as const,\n\t\t\tagent,\n\t\t})),\n\t\t...(remainingHumanAgentsCount > 0\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"count\" as const,\n\t\t\t\t\t\tcount: remainingHumanAgentsCount,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(hideDefaultAIAgent\n\t\t\t? []\n\t\t\t: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"ai\" as const,\n\t\t\t\t\t\tagent: aiAgents[0],\n\t\t\t\t\t},\n\t\t\t\t]),\n\t];\n\n\treturn useRenderElement(\n\t\t\"div\",\n\t\t{ className },\n\t\t{\n\t\t\tprops: {\n\t\t\t\tclassName: \"inline-grid items-center\",\n\t\t\t\tstyle: {\n\t\t\t\t\tgridTemplateColumns: `repeat(${items.length}, ${spacing}px)`,\n\t\t\t\t},\n\t\t\t\tchildren: items.map((item, index) => (\n\t\t\t\t\t<AvatarStackItem\n\t\t\t\t\t\tgapWidth={gapWidth}\n\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\tkey={`avatar-${index}`}\n\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\tspacing={spacing}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.type === \"human\" && (\n\t\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\t\tclassName={cn(\"size-full\")}\n\t\t\t\t\t\t\t\timage={item.agent.image}\n\t\t\t\t\t\t\t\tname={item.agent.name}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{item.type === \"count\" && (\n\t\t\t\t\t\t\t<div className=\"flex size-full items-center justify-center rounded-full bg-co-background-200 font-medium text-co-text-900 text-sm dark:bg-co-background-500\">\n\t\t\t\t\t\t\t\t+{item.count}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{item.type === \"ai\" && (\n\t\t\t\t\t\t\t<div className=\"flex size-full items-center justify-center rounded-full bg-co-background-200 dark:bg-co-background-600\">\n\t\t\t\t\t\t\t\t<CossistantLogo className=\"h-[50%] min-h-4 w-[50%] min-w-4\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</AvatarStackItem>\n\t\t\t\t)),\n\t\t\t},\n\t\t}\n\t);\n}\n"],"mappings":";;;;;;;AAqBA,MAAa,mBAAmB,EAC/B,UACA,OACA,OAAO,IACP,UAAU,IACV,WAAW,GACX,gBAQ0B;CAC1B,MAAM,UAAU,UAAU;CAG1B,MAAM,eAAe,OAAO;CAC5B,MAAM,eAAe,eAAe;CACpC,MAAM,iBAAiB,GAAG,eAAe,QAAQ;AAEjD,QAAO,iBACN,OACA,EAAE,WAAW,EACb,EACC,OAAO;EACN,WAAW,GACV,oCACA,CAAC,WAAW,gDACZ;EACD,OAAO;GACN,OAAO,GAAG,KAAK;GACf,QAAQ,GAAG,KAAK;GAEhB,GAAI,UACD,EAAE,GACF;IACA,MAAM,mBAAmB,aAAa,KAAK,aAAa,QAAQ,eAAe,oBAAoB,aAAa,YAAY,aAAa;IACzI,YAAY,mBAAmB,aAAa,KAAK,aAAa,QAAQ,eAAe,oBAAoB,aAAa,YAAY,aAAa;IAC/I;GACH;EACD;EACA,EACD,CACD;;;;;;AAOF,SAAgB,YAAY,EAC3B,aACA,UACA,eAAe,OACf,qBAAqB,MACrB,WACA,OAAO,IACP,UAAU,IACV,WAAW,KAC8B;CACzC,MAAM,uBAAuB,YAAY,MAAM,GAAG,EAAE;CACpD,MAAM,4BAA4B,KAAK,IAAI,GAAG,YAAY,SAAS,EAAE;CAGrE,MAAM,QAAQ;EACb,GAAG,qBAAqB,KAAK,WAAW;GACvC,MAAM;GACN;GACA,EAAE;EACH,GAAI,4BAA4B,IAC7B,CACA;GACC,MAAM;GACN,OAAO;GACP,CACD,GACA,EAAE;EACL,GAAI,qBACD,EAAE,GACF,CACA;GACC,MAAM;GACN,OAAO,SAAS;GAChB,CACD;EACH;AAED,QAAO,iBACN,OACA,EAAE,WAAW,EACb,EACC,OAAO;EACN,WAAW;EACX,OAAO,EACN,qBAAqB,UAAU,MAAM,OAAO,IAAI,QAAQ,MACxD;EACD,UAAU,MAAM,KAAK,MAAM,UAC1B,qBAAC;GACU;GACH;GAED;GACG;;IAER,KAAK,SAAS,WACd,oBAAC;KACA,WAAW,GAAG,YAAY;KAC1B,OAAO,KAAK,MAAM;KAClB,MAAM,KAAK,MAAM;MAChB;IAEF,KAAK,SAAS,WACd,qBAAC;KAAI,WAAU;gBAA8I,KAC1J,KAAK;MACF;IAEN,KAAK,SAAS,QACd,oBAAC;KAAI,WAAU;eACd,oBAAC,kBAAe,WAAU,oCAAoC;MACzD;;KAnBF,UAAU,QAqBE,CACjB;EACF,EACD,CACD"}
|