@cossistant/core 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/rolldown_runtime.js +33 -0
- package/dist/client.d.ts +82 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +275 -0
- package/dist/client.js.map +1 -0
- package/dist/contact.d.ts +28 -0
- package/dist/contact.d.ts.map +1 -0
- package/dist/conversation.d.ts +85 -0
- package/dist/conversation.d.ts.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +16 -0
- package/dist/locale-utils.d.ts +17 -0
- package/dist/locale-utils.d.ts.map +1 -0
- package/dist/locale-utils.js +22 -0
- package/dist/locale-utils.js.map +1 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +22 -0
- package/dist/logger.js.map +1 -0
- package/dist/realtime-events.d.ts +120 -0
- package/dist/realtime-events.d.ts.map +1 -0
- package/dist/rest-client.d.ts +65 -0
- package/dist/rest-client.d.ts.map +1 -0
- package/dist/rest-client.js +367 -0
- package/dist/rest-client.js.map +1 -0
- package/dist/schemas.d.ts +33 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/store/conversations-store.d.ts +22 -0
- package/dist/store/conversations-store.d.ts.map +1 -0
- package/dist/store/conversations-store.js +108 -0
- package/dist/store/conversations-store.js.map +1 -0
- package/dist/store/create-store.d.ts +14 -0
- package/dist/store/create-store.d.ts.map +1 -0
- package/dist/store/create-store.js +47 -0
- package/dist/store/create-store.js.map +1 -0
- package/dist/store/seen-store.d.ts +37 -0
- package/dist/store/seen-store.d.ts.map +1 -0
- package/dist/store/seen-store.js +131 -0
- package/dist/store/seen-store.js.map +1 -0
- package/dist/store/support-store.d.ts +63 -0
- package/dist/store/support-store.d.ts.map +1 -0
- package/dist/store/support-store.js +170 -0
- package/dist/store/support-store.js.map +1 -0
- package/dist/store/timeline-items-store.d.ts +27 -0
- package/dist/store/timeline-items-store.d.ts.map +1 -0
- package/dist/store/timeline-items-store.js +142 -0
- package/dist/store/timeline-items-store.js.map +1 -0
- package/dist/store/typing-store.d.ts +50 -0
- package/dist/store/typing-store.d.ts.map +1 -0
- package/dist/store/typing-store.js +149 -0
- package/dist/store/typing-store.js.map +1 -0
- package/dist/store/website-store.d.ts +24 -0
- package/dist/store/website-store.d.ts.map +1 -0
- package/dist/store/website-store.js +60 -0
- package/dist/store/website-store.js.map +1 -0
- package/dist/timeline-item.d.ts +207 -0
- package/dist/timeline-item.d.ts.map +1 -0
- package/dist/types/src/enums.js +24 -0
- package/dist/types/src/enums.js.map +1 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +20 -0
- package/dist/utils.js.map +1 -0
- package/dist/visitor-data.d.ts +33 -0
- package/dist/visitor-data.d.ts.map +1 -0
- package/dist/visitor-data.js +212 -0
- package/dist/visitor-data.js.map +1 -0
- package/dist/visitor-tracker.d.ts +31 -0
- package/dist/visitor-tracker.d.ts.map +1 -0
- package/dist/visitor-tracker.js +109 -0
- package/dist/visitor-tracker.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { createStore } from "./create-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/store/support-store.ts
|
|
4
|
+
const STORAGE_KEY = "cossistant-support-store";
|
|
5
|
+
function createDefaultNavigation() {
|
|
6
|
+
return {
|
|
7
|
+
current: { page: "HOME" },
|
|
8
|
+
previousPages: []
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function createDefaultConfig() {
|
|
12
|
+
return {
|
|
13
|
+
size: "normal",
|
|
14
|
+
content: {},
|
|
15
|
+
isOpen: false
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function createDefaultState() {
|
|
19
|
+
return {
|
|
20
|
+
navigation: createDefaultNavigation(),
|
|
21
|
+
config: createDefaultConfig()
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function cloneNavigationState(state) {
|
|
25
|
+
switch (state.page) {
|
|
26
|
+
case "CONVERSATION": return {
|
|
27
|
+
page: "CONVERSATION",
|
|
28
|
+
params: { ...state.params }
|
|
29
|
+
};
|
|
30
|
+
default: return {
|
|
31
|
+
page: state.page,
|
|
32
|
+
params: state.params
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function parsePersistedState(persisted, fallback) {
|
|
37
|
+
if (!persisted) return fallback;
|
|
38
|
+
const persistedNavigation = persisted.navigation;
|
|
39
|
+
return {
|
|
40
|
+
navigation: {
|
|
41
|
+
current: persistedNavigation?.current ? cloneNavigationState(persistedNavigation.current) : cloneNavigationState(fallback.navigation.current),
|
|
42
|
+
previousPages: (persistedNavigation?.previousPages ?? fallback.navigation.previousPages).map((page) => cloneNavigationState(page))
|
|
43
|
+
},
|
|
44
|
+
config: {
|
|
45
|
+
...fallback.config,
|
|
46
|
+
...persisted.config
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function getInitialState(options) {
|
|
51
|
+
const fallback = createDefaultState();
|
|
52
|
+
const storage = options.storage;
|
|
53
|
+
if (!storage) return fallback;
|
|
54
|
+
try {
|
|
55
|
+
const raw = storage.getItem(options.storageKey ?? STORAGE_KEY);
|
|
56
|
+
if (!raw) return fallback;
|
|
57
|
+
return parsePersistedState(JSON.parse(raw), fallback);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.warn("[SupportStore] Failed to read persisted state", error);
|
|
60
|
+
return fallback;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function persistState(state, options) {
|
|
64
|
+
const storage = options.storage;
|
|
65
|
+
if (!storage) return;
|
|
66
|
+
const data = {
|
|
67
|
+
navigation: {
|
|
68
|
+
current: state.navigation.current,
|
|
69
|
+
previousPages: [...state.navigation.previousPages]
|
|
70
|
+
},
|
|
71
|
+
config: {
|
|
72
|
+
size: state.config.size,
|
|
73
|
+
isOpen: state.config.isOpen
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
try {
|
|
77
|
+
storage.setItem(options.storageKey ?? STORAGE_KEY, JSON.stringify(data));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.warn("[SupportStore] Failed to persist state", error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function createSupportStore(options = {}) {
|
|
83
|
+
const store = createStore(getInitialState(options));
|
|
84
|
+
const commit = (updater) => {
|
|
85
|
+
const previous = store.getState();
|
|
86
|
+
store.setState(updater);
|
|
87
|
+
const next = store.getState();
|
|
88
|
+
if (next !== previous) persistState(next, options);
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
...store,
|
|
92
|
+
navigate(state) {
|
|
93
|
+
commit((current) => ({
|
|
94
|
+
navigation: {
|
|
95
|
+
previousPages: [...current.navigation.previousPages, current.navigation.current],
|
|
96
|
+
current: state
|
|
97
|
+
},
|
|
98
|
+
config: current.config
|
|
99
|
+
}));
|
|
100
|
+
},
|
|
101
|
+
replace(state) {
|
|
102
|
+
commit((current) => ({
|
|
103
|
+
navigation: {
|
|
104
|
+
...current.navigation,
|
|
105
|
+
current: state
|
|
106
|
+
},
|
|
107
|
+
config: current.config
|
|
108
|
+
}));
|
|
109
|
+
},
|
|
110
|
+
goBack() {
|
|
111
|
+
commit((current) => {
|
|
112
|
+
const { previousPages } = current.navigation;
|
|
113
|
+
if (previousPages.length === 0) return current;
|
|
114
|
+
const nextPrevious = previousPages.slice(0, -1);
|
|
115
|
+
const previous = previousPages.at(-1);
|
|
116
|
+
if (!previous) return current;
|
|
117
|
+
return {
|
|
118
|
+
navigation: {
|
|
119
|
+
previousPages: nextPrevious,
|
|
120
|
+
current: previous
|
|
121
|
+
},
|
|
122
|
+
config: current.config
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
open() {
|
|
127
|
+
commit((current) => ({
|
|
128
|
+
navigation: current.navigation,
|
|
129
|
+
config: {
|
|
130
|
+
...current.config,
|
|
131
|
+
isOpen: true
|
|
132
|
+
}
|
|
133
|
+
}));
|
|
134
|
+
},
|
|
135
|
+
close() {
|
|
136
|
+
commit((current) => ({
|
|
137
|
+
navigation: current.navigation,
|
|
138
|
+
config: {
|
|
139
|
+
...current.config,
|
|
140
|
+
isOpen: false
|
|
141
|
+
}
|
|
142
|
+
}));
|
|
143
|
+
},
|
|
144
|
+
toggle() {
|
|
145
|
+
commit((current) => ({
|
|
146
|
+
navigation: current.navigation,
|
|
147
|
+
config: {
|
|
148
|
+
...current.config,
|
|
149
|
+
isOpen: !current.config.isOpen
|
|
150
|
+
}
|
|
151
|
+
}));
|
|
152
|
+
},
|
|
153
|
+
updateConfig(config) {
|
|
154
|
+
commit((current) => ({
|
|
155
|
+
navigation: current.navigation,
|
|
156
|
+
config: {
|
|
157
|
+
...current.config,
|
|
158
|
+
...config
|
|
159
|
+
}
|
|
160
|
+
}));
|
|
161
|
+
},
|
|
162
|
+
reset() {
|
|
163
|
+
commit(() => createDefaultState());
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
export { createSupportStore };
|
|
170
|
+
//# sourceMappingURL=support-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support-store.js","names":["data: PersistedState"],"sources":["../../src/store/support-store.ts"],"sourcesContent":["import { createStore, type Store } from \"./create-store\";\n\nexport type NavigationState =\n\t| { page: \"HOME\"; params?: undefined }\n\t| { page: \"ARTICLES\"; params?: undefined }\n\t| {\n\t\t\tpage: \"CONVERSATION\";\n\t\t\tparams: { conversationId: string; initialMessage?: string };\n\t }\n\t| { page: \"CONVERSATION_HISTORY\"; params?: undefined };\n\nexport type SUPPORT_PAGES = NavigationState[\"page\"];\n\nexport type SupportNavigation = {\n\tpreviousPages: NavigationState[];\n\tcurrent: NavigationState;\n};\n\nexport type SupportConfig = {\n\tsize: \"normal\" | \"larger\";\n\tisOpen: boolean;\n\tcontent: {\n\t\thome?: {\n\t\t\theader?: string;\n\t\t\tsubheader?: string;\n\t\t\tctaLabel?: string;\n\t\t};\n\t};\n};\n\nexport type SupportStoreState = {\n\tnavigation: SupportNavigation;\n\tconfig: SupportConfig;\n};\n\nexport type SupportStoreActions = {\n\tnavigate(state: NavigationState): void;\n\treplace(state: NavigationState): void;\n\tgoBack(): void;\n\topen(): void;\n\tclose(): void;\n\ttoggle(): void;\n\tupdateConfig(config: Partial<SupportConfig>): void;\n\treset(): void;\n};\n\nexport type SupportStoreStorage = {\n\tgetItem(key: string): string | null;\n\tsetItem(key: string, value: string): void;\n\tremoveItem(key: string): void;\n};\n\nexport type SupportStoreOptions = {\n\tstorage?: SupportStoreStorage;\n\tstorageKey?: string;\n};\n\nexport type SupportStore = Store<SupportStoreState> & SupportStoreActions;\n\nconst STORAGE_KEY = \"cossistant-support-store\";\n\ntype PersistedConfig = Pick<SupportConfig, \"size\" | \"isOpen\">;\n\ntype PersistedState = {\n\tnavigation?: SupportNavigation;\n\tconfig?: PersistedConfig;\n};\n\nfunction createDefaultNavigation(): SupportNavigation {\n\treturn {\n\t\tcurrent: { page: \"HOME\" },\n\t\tpreviousPages: [],\n\t};\n}\n\nfunction createDefaultConfig(): SupportConfig {\n\treturn {\n\t\tsize: \"normal\",\n\t\tcontent: {},\n\t\tisOpen: false,\n\t};\n}\n\nfunction createDefaultState(): SupportStoreState {\n\treturn {\n\t\tnavigation: createDefaultNavigation(),\n\t\tconfig: createDefaultConfig(),\n\t};\n}\n\nfunction cloneNavigationState(state: NavigationState): NavigationState {\n\tswitch (state.page) {\n\t\tcase \"CONVERSATION\":\n\t\t\treturn {\n\t\t\t\tpage: \"CONVERSATION\",\n\t\t\t\tparams: { ...state.params },\n\t\t\t};\n\t\tdefault:\n\t\t\treturn { page: state.page, params: state.params } as NavigationState;\n\t}\n}\n\nfunction parsePersistedState(\n\tpersisted: PersistedState | null | undefined,\n\tfallback: SupportStoreState\n): SupportStoreState {\n\tif (!persisted) {\n\t\treturn fallback;\n\t}\n\n\tconst persistedNavigation = persisted.navigation;\n\tconst navigation: SupportNavigation = {\n\t\tcurrent: persistedNavigation?.current\n\t\t\t? cloneNavigationState(persistedNavigation.current)\n\t\t\t: cloneNavigationState(fallback.navigation.current),\n\t\tpreviousPages: (\n\t\t\tpersistedNavigation?.previousPages ?? fallback.navigation.previousPages\n\t\t).map((page) => cloneNavigationState(page)),\n\t};\n\n\tconst config: SupportConfig = {\n\t\t...fallback.config,\n\t\t...persisted.config,\n\t};\n\n\treturn {\n\t\tnavigation,\n\t\tconfig,\n\t};\n}\n\nfunction getInitialState(options: SupportStoreOptions): SupportStoreState {\n\tconst fallback = createDefaultState();\n\tconst storage = options.storage;\n\tif (!storage) {\n\t\treturn fallback;\n\t}\n\n\ttry {\n\t\tconst raw = storage.getItem(options.storageKey ?? STORAGE_KEY);\n\t\tif (!raw) {\n\t\t\treturn fallback;\n\t\t}\n\n\t\tconst parsed = JSON.parse(raw) as PersistedState;\n\t\treturn parsePersistedState(parsed, fallback);\n\t} catch (error) {\n\t\tconsole.warn(\"[SupportStore] Failed to read persisted state\", error);\n\t\treturn fallback;\n\t}\n}\n\nfunction persistState(\n\tstate: SupportStoreState,\n\toptions: SupportStoreOptions\n): void {\n\tconst storage = options.storage;\n\tif (!storage) {\n\t\treturn;\n\t}\n\n\tconst data: PersistedState = {\n\t\tnavigation: {\n\t\t\tcurrent: state.navigation.current,\n\t\t\tpreviousPages: [...state.navigation.previousPages],\n\t\t},\n\t\tconfig: {\n\t\t\tsize: state.config.size,\n\t\t\tisOpen: state.config.isOpen,\n\t\t},\n\t};\n\n\ttry {\n\t\tstorage.setItem(options.storageKey ?? STORAGE_KEY, JSON.stringify(data));\n\t} catch (error) {\n\t\tconsole.warn(\"[SupportStore] Failed to persist state\", error);\n\t}\n}\n\nexport function createSupportStore(\n\toptions: SupportStoreOptions = {}\n): SupportStore {\n\tconst initialState = getInitialState(options);\n\tconst store = createStore<SupportStoreState>(initialState);\n\n\tconst commit = (updater: (state: SupportStoreState) => SupportStoreState) => {\n\t\tconst previous = store.getState();\n\t\tstore.setState(updater);\n\t\tconst next = store.getState();\n\t\tif (next !== previous) {\n\t\t\tpersistState(next, options);\n\t\t}\n\t};\n\n\treturn {\n\t\t...store,\n\t\tnavigate(state) {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: {\n\t\t\t\t\tpreviousPages: [\n\t\t\t\t\t\t...current.navigation.previousPages,\n\t\t\t\t\t\tcurrent.navigation.current,\n\t\t\t\t\t],\n\t\t\t\t\tcurrent: state,\n\t\t\t\t},\n\t\t\t\tconfig: current.config,\n\t\t\t}));\n\t\t},\n\t\treplace(state) {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: {\n\t\t\t\t\t...current.navigation,\n\t\t\t\t\tcurrent: state,\n\t\t\t\t},\n\t\t\t\tconfig: current.config,\n\t\t\t}));\n\t\t},\n\t\tgoBack() {\n\t\t\tcommit((current) => {\n\t\t\t\tconst { previousPages } = current.navigation;\n\t\t\t\tif (previousPages.length === 0) {\n\t\t\t\t\treturn current;\n\t\t\t\t}\n\n\t\t\t\tconst nextPrevious = previousPages.slice(0, -1);\n\t\t\t\tconst previous = previousPages.at(-1);\n\n\t\t\t\tif (!previous) {\n\t\t\t\t\treturn current;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tnavigation: {\n\t\t\t\t\t\tpreviousPages: nextPrevious,\n\t\t\t\t\t\tcurrent: previous,\n\t\t\t\t\t},\n\t\t\t\t\tconfig: current.config,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\topen() {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: current.navigation,\n\t\t\t\tconfig: { ...current.config, isOpen: true },\n\t\t\t}));\n\t\t},\n\t\tclose() {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: current.navigation,\n\t\t\t\tconfig: { ...current.config, isOpen: false },\n\t\t\t}));\n\t\t},\n\t\ttoggle() {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: current.navigation,\n\t\t\t\tconfig: { ...current.config, isOpen: !current.config.isOpen },\n\t\t\t}));\n\t\t},\n\t\tupdateConfig(config) {\n\t\t\tcommit((current) => ({\n\t\t\t\tnavigation: current.navigation,\n\t\t\t\tconfig: { ...current.config, ...config },\n\t\t\t}));\n\t\t},\n\t\treset() {\n\t\t\tcommit(() => createDefaultState());\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TimelineItem } from "../timeline-item.js";
|
|
2
|
+
import { Store } from "./create-store.js";
|
|
3
|
+
import { RealtimeEvent } from "@cossistant/types";
|
|
4
|
+
|
|
5
|
+
//#region src/store/timeline-items-store.d.ts
|
|
6
|
+
type TimelineItemCreatedEvent = RealtimeEvent<"timelineItemCreated">;
|
|
7
|
+
type ConversationTimelineItemsState = {
|
|
8
|
+
items: TimelineItem[];
|
|
9
|
+
hasNextPage: boolean;
|
|
10
|
+
nextCursor?: string;
|
|
11
|
+
};
|
|
12
|
+
type TimelineItemsState = {
|
|
13
|
+
conversations: Record<string, ConversationTimelineItemsState>;
|
|
14
|
+
};
|
|
15
|
+
type TimelineItemsStore = Store<TimelineItemsState> & {
|
|
16
|
+
ingestPage(conversationId: string, page: ConversationTimelineItemsState): void;
|
|
17
|
+
ingestTimelineItem(item: TimelineItem): void;
|
|
18
|
+
ingestRealtimeTimelineItem(event: TimelineItemCreatedEvent): TimelineItem;
|
|
19
|
+
removeTimelineItem(conversationId: string, itemId: string): void;
|
|
20
|
+
finalizeTimelineItem(conversationId: string, optimisticId: string, item: TimelineItem): void;
|
|
21
|
+
clearConversation(conversationId: string): void;
|
|
22
|
+
};
|
|
23
|
+
declare function createTimelineItemsStore(initialState?: TimelineItemsState): TimelineItemsStore;
|
|
24
|
+
declare function getConversationTimelineItems(store: Store<TimelineItemsState>, conversationId: string): ConversationTimelineItemsState | undefined;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { ConversationTimelineItemsState, TimelineItemsState, TimelineItemsStore, createTimelineItemsStore, getConversationTimelineItems };
|
|
27
|
+
//# sourceMappingURL=timeline-items-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-items-store.d.ts","names":[],"sources":["../../src/store/timeline-items-store.ts"],"sourcesContent":[],"mappings":";;;;;KAOK,wBAAA,GAA2B;KAEpB,8BAAA;EAFP,KAAA,EAGG,YAHH,EAAA;EAEO,WAAA,EAAA,OAAA;EAMA,UAAA,CAAA,EAAA,MAAA;AA8LZ,CAAA;AAAuC,KA9L3B,kBAAA,GA8L2B;EAAN,aAAA,EA7LjB,MA6LiB,CAAA,MAAA,EA7LF,8BA6LE,CAAA;CAGzB;AAEkB,KALd,kBAAA,GAAqB,KAKP,CALa,kBAKb,CAAA,GAAA;EACS,UAAA,CAAA,cAAA,EAAA,MAAA,EAAA,IAAA,EAH3B,8BAG2B,CAAA,EAAA,IAAA;EAA2B,kBAAA,CAAA,IAAA,EADpC,YACoC,CAAA,EAAA,IAAA;EAKtD,0BAAA,CAAA,KAAA,EAL2B,wBAK3B,CAAA,EALsD,YAKtD;EAAY,kBAAA,CAAA,cAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,CAAA,EAAA,IAAA;EAKJ,oBAAA,CAAA,cAAwB,EAAA,MACzB,EAAA,YAAA,EACZ,MAAA,EAAA,IAAA,EAPK,YAOa,CAAA,EAAA,IAAA;EA2CL,iBAAA,CAAA,cAA4B,EAAA,MAAA,CAAA,EAAA,IAAA;CAC9B;AAAN,iBA9CQ,wBAAA,CA8CR,YAAA,CAAA,EA7CO,kBA6CP,CAAA,EA5CL,kBA4CK;AAEL,iBAHa,4BAAA,CAGb,KAAA,EAFK,KAEL,CAFW,kBAEX,CAAA,EAAA,cAAA,EAAA,MAAA,CAAA,EAAA,8BAAA,GAAA,SAAA"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createStore } from "./create-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/store/timeline-items-store.ts
|
|
4
|
+
const INITIAL_STATE = { conversations: {} };
|
|
5
|
+
function sortTimelineItems(items) {
|
|
6
|
+
return [...items].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
7
|
+
}
|
|
8
|
+
function isSameTimelineItem(a, b) {
|
|
9
|
+
return a.id === b.id && a.text === b.text && new Date(a.createdAt).getTime() === new Date(b.createdAt).getTime();
|
|
10
|
+
}
|
|
11
|
+
function mergeTimelineItems(existing, incoming) {
|
|
12
|
+
if (incoming.length === 0) return existing;
|
|
13
|
+
const byId = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const item of existing) if (item.id) byId.set(item.id, item);
|
|
15
|
+
let changed = false;
|
|
16
|
+
for (const item of incoming) {
|
|
17
|
+
if (!item.id) continue;
|
|
18
|
+
const previous = byId.get(item.id);
|
|
19
|
+
if (!(previous && isSameTimelineItem(previous, item))) changed = true;
|
|
20
|
+
byId.set(item.id, item);
|
|
21
|
+
}
|
|
22
|
+
if (!changed && byId.size === existing.length) {
|
|
23
|
+
let orderStable = true;
|
|
24
|
+
for (const item of existing) if (item.id && byId.get(item.id) !== item) {
|
|
25
|
+
orderStable = false;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
if (orderStable) return existing;
|
|
29
|
+
}
|
|
30
|
+
return sortTimelineItems(Array.from(byId.values()));
|
|
31
|
+
}
|
|
32
|
+
function applyPage(state, conversationId, page) {
|
|
33
|
+
const existing = state.conversations[conversationId];
|
|
34
|
+
const mergedItems = mergeTimelineItems(existing?.items ?? [], page.items);
|
|
35
|
+
if (existing && existing.items === mergedItems && existing.hasNextPage === page.hasNextPage && existing.nextCursor === page.nextCursor) return state;
|
|
36
|
+
return {
|
|
37
|
+
...state,
|
|
38
|
+
conversations: {
|
|
39
|
+
...state.conversations,
|
|
40
|
+
[conversationId]: {
|
|
41
|
+
items: mergedItems,
|
|
42
|
+
hasNextPage: page.hasNextPage,
|
|
43
|
+
nextCursor: page.nextCursor
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function applyTimelineItem(state, item) {
|
|
49
|
+
const existing = state.conversations[item.conversationId];
|
|
50
|
+
const mergedItems = mergeTimelineItems(existing?.items ?? [], [item]);
|
|
51
|
+
if (existing && existing.items === mergedItems) return state;
|
|
52
|
+
return {
|
|
53
|
+
...state,
|
|
54
|
+
conversations: {
|
|
55
|
+
...state.conversations,
|
|
56
|
+
[item.conversationId]: {
|
|
57
|
+
items: mergedItems,
|
|
58
|
+
hasNextPage: existing?.hasNextPage ?? false,
|
|
59
|
+
nextCursor: existing?.nextCursor
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function removeTimelineItem(state, conversationId, itemId) {
|
|
65
|
+
const existing = state.conversations[conversationId];
|
|
66
|
+
if (!existing) return state;
|
|
67
|
+
const index = existing.items.findIndex((item) => item.id === itemId);
|
|
68
|
+
if (index === -1) return state;
|
|
69
|
+
const nextItems = existing.items.slice(0, index).concat(existing.items.slice(index + 1));
|
|
70
|
+
const nextConversation = {
|
|
71
|
+
...existing,
|
|
72
|
+
items: nextItems
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
...state,
|
|
76
|
+
conversations: {
|
|
77
|
+
...state.conversations,
|
|
78
|
+
[conversationId]: nextConversation
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function finalizeTimelineItem(state, conversationId, optimisticId, item) {
|
|
83
|
+
return applyTimelineItem(removeTimelineItem(state, conversationId, optimisticId), item);
|
|
84
|
+
}
|
|
85
|
+
function normalizeRealtimeTimelineItem(event) {
|
|
86
|
+
const raw = event.payload.item;
|
|
87
|
+
return {
|
|
88
|
+
id: raw.id,
|
|
89
|
+
conversationId: raw.conversationId,
|
|
90
|
+
organizationId: raw.organizationId,
|
|
91
|
+
visibility: raw.visibility,
|
|
92
|
+
type: raw.type,
|
|
93
|
+
text: raw.text ?? null,
|
|
94
|
+
parts: raw.parts,
|
|
95
|
+
tool: raw.tool ?? null,
|
|
96
|
+
userId: raw.userId,
|
|
97
|
+
visitorId: raw.visitorId,
|
|
98
|
+
aiAgentId: raw.aiAgentId,
|
|
99
|
+
createdAt: raw.createdAt,
|
|
100
|
+
deletedAt: raw.deletedAt ?? null
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function createTimelineItemsStore(initialState = INITIAL_STATE) {
|
|
104
|
+
const store = createStore(initialState);
|
|
105
|
+
return {
|
|
106
|
+
...store,
|
|
107
|
+
ingestPage(conversationId, page) {
|
|
108
|
+
store.setState((state) => applyPage(state, conversationId, page));
|
|
109
|
+
},
|
|
110
|
+
ingestTimelineItem(item) {
|
|
111
|
+
store.setState((state) => applyTimelineItem(state, item));
|
|
112
|
+
},
|
|
113
|
+
ingestRealtimeTimelineItem(event) {
|
|
114
|
+
const item = normalizeRealtimeTimelineItem(event);
|
|
115
|
+
store.setState((state) => applyTimelineItem(state, item));
|
|
116
|
+
return item;
|
|
117
|
+
},
|
|
118
|
+
removeTimelineItem(conversationId, itemId) {
|
|
119
|
+
store.setState((state) => removeTimelineItem(state, conversationId, itemId));
|
|
120
|
+
},
|
|
121
|
+
finalizeTimelineItem(conversationId, optimisticId, item) {
|
|
122
|
+
store.setState((state) => finalizeTimelineItem(state, conversationId, optimisticId, item));
|
|
123
|
+
},
|
|
124
|
+
clearConversation(conversationId) {
|
|
125
|
+
store.setState((state) => {
|
|
126
|
+
if (!state.conversations[conversationId]) return state;
|
|
127
|
+
const { [conversationId]: _removed,...rest } = state.conversations;
|
|
128
|
+
return {
|
|
129
|
+
...state,
|
|
130
|
+
conversations: rest
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function getConversationTimelineItems(store, conversationId) {
|
|
137
|
+
return store.getState().conversations[conversationId];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//#endregion
|
|
141
|
+
export { createTimelineItemsStore, getConversationTimelineItems };
|
|
142
|
+
//# sourceMappingURL=timeline-items-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-items-store.js","names":["INITIAL_STATE: TimelineItemsState","nextConversation: ConversationTimelineItemsState"],"sources":["../../src/store/timeline-items-store.ts"],"sourcesContent":["import type { RealtimeEvent } from \"@cossistant/types\";\nimport type {\n\tTimelineItem,\n\tTimelineItemParts,\n} from \"@cossistant/types/api/timeline-item\";\nimport { createStore, type Store } from \"./create-store\";\n\ntype TimelineItemCreatedEvent = RealtimeEvent<\"timelineItemCreated\">;\n\nexport type ConversationTimelineItemsState = {\n\titems: TimelineItem[];\n\thasNextPage: boolean;\n\tnextCursor?: string;\n};\n\nexport type TimelineItemsState = {\n\tconversations: Record<string, ConversationTimelineItemsState>;\n};\n\nconst INITIAL_STATE: TimelineItemsState = {\n\tconversations: {},\n};\n\nfunction sortTimelineItems(items: TimelineItem[]): TimelineItem[] {\n\treturn [...items].sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n}\n\nfunction isSameTimelineItem(a: TimelineItem, b: TimelineItem): boolean {\n\treturn (\n\t\ta.id === b.id &&\n\t\ta.text === b.text &&\n\t\tnew Date(a.createdAt).getTime() === new Date(b.createdAt).getTime()\n\t);\n}\n\nfunction mergeTimelineItems(\n\texisting: TimelineItem[],\n\tincoming: TimelineItem[]\n): TimelineItem[] {\n\tif (incoming.length === 0) {\n\t\treturn existing;\n\t}\n\n\tconst byId = new Map<string, TimelineItem>();\n\tfor (const item of existing) {\n\t\tif (item.id) {\n\t\t\tbyId.set(item.id, item);\n\t\t}\n\t}\n\n\tlet changed = false;\n\tfor (const item of incoming) {\n\t\tif (!item.id) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst previous = byId.get(item.id);\n\t\tif (!(previous && isSameTimelineItem(previous, item))) {\n\t\t\tchanged = true;\n\t\t}\n\t\tbyId.set(item.id, item);\n\t}\n\n\tif (!changed && byId.size === existing.length) {\n\t\tlet orderStable = true;\n\t\tfor (const item of existing) {\n\t\t\tif (item.id && byId.get(item.id) !== item) {\n\t\t\t\torderStable = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (orderStable) {\n\t\t\treturn existing;\n\t\t}\n\t}\n\n\treturn sortTimelineItems(Array.from(byId.values()));\n}\n\nfunction applyPage(\n\tstate: TimelineItemsState,\n\tconversationId: string,\n\tpage: Pick<\n\t\tConversationTimelineItemsState,\n\t\t\"items\" | \"hasNextPage\" | \"nextCursor\"\n\t>\n): TimelineItemsState {\n\tconst existing = state.conversations[conversationId];\n\tconst mergedItems = mergeTimelineItems(existing?.items ?? [], page.items);\n\n\tif (\n\t\texisting &&\n\t\texisting.items === mergedItems &&\n\t\texisting.hasNextPage === page.hasNextPage &&\n\t\texisting.nextCursor === page.nextCursor\n\t) {\n\t\treturn state;\n\t}\n\n\treturn {\n\t\t...state,\n\t\tconversations: {\n\t\t\t...state.conversations,\n\t\t\t[conversationId]: {\n\t\t\t\titems: mergedItems,\n\t\t\t\thasNextPage: page.hasNextPage,\n\t\t\t\tnextCursor: page.nextCursor,\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction applyTimelineItem(\n\tstate: TimelineItemsState,\n\titem: TimelineItem\n): TimelineItemsState {\n\tconst existing = state.conversations[item.conversationId];\n\tconst mergedItems = mergeTimelineItems(existing?.items ?? [], [item]);\n\n\tif (existing && existing.items === mergedItems) {\n\t\treturn state;\n\t}\n\n\treturn {\n\t\t...state,\n\t\tconversations: {\n\t\t\t...state.conversations,\n\t\t\t[item.conversationId]: {\n\t\t\t\titems: mergedItems,\n\t\t\t\thasNextPage: existing?.hasNextPage ?? false,\n\t\t\t\tnextCursor: existing?.nextCursor,\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction removeTimelineItem(\n\tstate: TimelineItemsState,\n\tconversationId: string,\n\titemId: string\n): TimelineItemsState {\n\tconst existing = state.conversations[conversationId];\n\tif (!existing) {\n\t\treturn state;\n\t}\n\n\tconst index = existing.items.findIndex((item) => item.id === itemId);\n\tif (index === -1) {\n\t\treturn state;\n\t}\n\n\tconst nextItems = existing.items\n\t\t.slice(0, index)\n\t\t.concat(existing.items.slice(index + 1));\n\n\tconst nextConversation: ConversationTimelineItemsState = {\n\t\t...existing,\n\t\titems: nextItems,\n\t};\n\n\treturn {\n\t\t...state,\n\t\tconversations: {\n\t\t\t...state.conversations,\n\t\t\t[conversationId]: nextConversation,\n\t\t},\n\t};\n}\n\nfunction finalizeTimelineItem(\n\tstate: TimelineItemsState,\n\tconversationId: string,\n\toptimisticId: string,\n\titem: TimelineItem\n): TimelineItemsState {\n\tconst withoutOptimistic = removeTimelineItem(\n\t\tstate,\n\t\tconversationId,\n\t\toptimisticId\n\t);\n\treturn applyTimelineItem(withoutOptimistic, item);\n}\n\n// Normalize timeline item created event\nfunction normalizeRealtimeTimelineItem(\n\tevent: TimelineItemCreatedEvent\n): TimelineItem {\n\tconst raw = event.payload.item;\n\treturn {\n\t\tid: raw.id,\n\t\tconversationId: raw.conversationId,\n\t\torganizationId: raw.organizationId,\n\t\tvisibility: raw.visibility,\n\t\ttype: raw.type,\n\t\ttext: raw.text ?? null,\n\t\tparts: raw.parts as TimelineItemParts,\n\t\ttool: raw.tool ?? null,\n\t\tuserId: raw.userId,\n\t\tvisitorId: raw.visitorId,\n\t\taiAgentId: raw.aiAgentId,\n\t\tcreatedAt: raw.createdAt,\n\t\tdeletedAt: raw.deletedAt ?? null,\n\t};\n}\n\nexport type TimelineItemsStore = Store<TimelineItemsState> & {\n\tingestPage(\n\t\tconversationId: string,\n\t\tpage: ConversationTimelineItemsState\n\t): void;\n\tingestTimelineItem(item: TimelineItem): void;\n\tingestRealtimeTimelineItem(event: TimelineItemCreatedEvent): TimelineItem;\n\tremoveTimelineItem(conversationId: string, itemId: string): void;\n\tfinalizeTimelineItem(\n\t\tconversationId: string,\n\t\toptimisticId: string,\n\t\titem: TimelineItem\n\t): void;\n\tclearConversation(conversationId: string): void;\n};\n\nexport function createTimelineItemsStore(\n\tinitialState: TimelineItemsState = INITIAL_STATE\n): TimelineItemsStore {\n\tconst store = createStore<TimelineItemsState>(initialState);\n\n\treturn {\n\t\t...store,\n\t\tingestPage(conversationId, page) {\n\t\t\tstore.setState((state) => applyPage(state, conversationId, page));\n\t\t},\n\t\tingestTimelineItem(item) {\n\t\t\tstore.setState((state) => applyTimelineItem(state, item));\n\t\t},\n\t\tingestRealtimeTimelineItem(event) {\n\t\t\tconst item = normalizeRealtimeTimelineItem(event);\n\t\t\tstore.setState((state) => applyTimelineItem(state, item));\n\t\t\treturn item;\n\t\t},\n\t\tremoveTimelineItem(conversationId, itemId) {\n\t\t\tstore.setState((state) =>\n\t\t\t\tremoveTimelineItem(state, conversationId, itemId)\n\t\t\t);\n\t\t},\n\t\tfinalizeTimelineItem(conversationId, optimisticId, item) {\n\t\t\tstore.setState((state) =>\n\t\t\t\tfinalizeTimelineItem(state, conversationId, optimisticId, item)\n\t\t\t);\n\t\t},\n\t\tclearConversation(conversationId) {\n\t\t\tstore.setState((state) => {\n\t\t\t\tif (!state.conversations[conversationId]) {\n\t\t\t\t\treturn state;\n\t\t\t\t}\n\n\t\t\t\tconst { [conversationId]: _removed, ...rest } = state.conversations;\n\n\t\t\t\treturn {\n\t\t\t\t\t...state,\n\t\t\t\t\tconversations: rest,\n\t\t\t\t} satisfies TimelineItemsState;\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport function getConversationTimelineItems(\n\tstore: Store<TimelineItemsState>,\n\tconversationId: string\n): ConversationTimelineItemsState | undefined {\n\treturn store.getState().conversations[conversationId];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Store } from "./create-store.js";
|
|
2
|
+
import { RealtimeEvent } from "../realtime-events.js";
|
|
3
|
+
|
|
4
|
+
//#region src/store/typing-store.d.ts
|
|
5
|
+
type TypingActorType = "visitor" | "user" | "ai_agent";
|
|
6
|
+
type TypingEntry = {
|
|
7
|
+
actorType: TypingActorType;
|
|
8
|
+
actorId: string;
|
|
9
|
+
preview: string | null;
|
|
10
|
+
updatedAt: number;
|
|
11
|
+
};
|
|
12
|
+
type ConversationTypingState = Record<string, TypingEntry>;
|
|
13
|
+
type TypingState = {
|
|
14
|
+
conversations: Record<string, ConversationTypingState>;
|
|
15
|
+
};
|
|
16
|
+
type TypingStoreDependencies = {
|
|
17
|
+
now?: () => number;
|
|
18
|
+
setTimeout?: (callback: () => void, delay: number) => unknown;
|
|
19
|
+
clearTimeout?: (id: unknown) => void;
|
|
20
|
+
defaultTtlMs?: number;
|
|
21
|
+
};
|
|
22
|
+
type TypingOptions = {
|
|
23
|
+
conversationId: string;
|
|
24
|
+
actorType: TypingActorType;
|
|
25
|
+
actorId: string;
|
|
26
|
+
};
|
|
27
|
+
type SetTypingOptions = TypingOptions & {
|
|
28
|
+
isTyping: boolean;
|
|
29
|
+
preview?: string | null;
|
|
30
|
+
ttlMs?: number;
|
|
31
|
+
};
|
|
32
|
+
type TypingStore = Store<TypingState> & {
|
|
33
|
+
setTyping(options: SetTypingOptions): void;
|
|
34
|
+
removeTyping(options: TypingOptions): void;
|
|
35
|
+
clearConversation(conversationId: string): void;
|
|
36
|
+
};
|
|
37
|
+
declare function createTypingStore(initialState?: TypingState, dependencies?: TypingStoreDependencies): TypingStore;
|
|
38
|
+
declare function setTypingState(store: TypingStore, options: SetTypingOptions): void;
|
|
39
|
+
declare function clearTypingState(store: TypingStore, options: TypingOptions): void;
|
|
40
|
+
declare function applyConversationTypingEvent(store: TypingStore, event: RealtimeEvent<"conversationTyping">, options?: {
|
|
41
|
+
ignoreVisitorId?: string | null;
|
|
42
|
+
ignoreUserId?: string | null;
|
|
43
|
+
ignoreAiAgentId?: string | null;
|
|
44
|
+
ttlMs?: number;
|
|
45
|
+
}): void;
|
|
46
|
+
declare function clearTypingFromTimelineItem(store: TypingStore, event: RealtimeEvent<"timelineItemCreated">): void;
|
|
47
|
+
declare function getConversationTyping(store: Store<TypingState>, conversationId: string): ConversationTypingState | undefined;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { ConversationTypingState, TypingActorType, TypingEntry, TypingState, TypingStore, TypingStoreDependencies, applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, createTypingStore, getConversationTyping, setTypingState };
|
|
50
|
+
//# sourceMappingURL=typing-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typing-store.d.ts","names":[],"sources":["../../src/store/typing-store.ts"],"sourcesContent":[],"mappings":";;;;KAGY,eAAA;KAEA,WAAA;EAFA,SAAA,EAGA,eAHe;EAEf,OAAA,EAAA,MAAW;EAOX,OAAA,EAAA,MAAA,GAAA,IAAA;EAEA,SAAA,EAAA,MAAW;AAMvB,CAAA;AAOK,KAfO,uBAAA,GAA0B,MAiB1B,CAAA,MAAe,EAjB0B,WAiB1B,CAAA;AAItB,KAnBO,WAAA,GAmBS;EAuCT,aAAA,EAzDI,MAyDO,CAAA,MAAA,EAzDQ,uBAyDR,CAAA;CAAS;AAAN,KApDd,uBAAA,GAoDc;EACN,GAAA,CAAA,EAAA,GAAA,GAAA,MAAA;EACG,UAAA,CAAA,EAAA,CAAA,QAAA,EAAA,GAAA,GAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,OAAA;EAAa,YAAA,CAAA,EAAA,CAAA,EAAA,EAAA,OAAA,EAAA,GAAA,IAAA;EAIpB,YAAA,CAAA,EAAA,MAAiB;CAClB;KApDV,aAAA,GAqDU;EACZ,cAAA,EAAA,MAAA;EAAW,SAAA,EApDF,eAoDE;EA+GE,OAAA,EAAA,MAAA;AAOhB,CAAA;AAOA,KA7KK,gBAAA,GAAmB,aA6KoB,GAAA;EA2D5B,QAAA,EAAA,OAAA;EA8BA,OAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EACF,KAAA,CAAA,EAAA,MAAA;CAAN;AAEL,KAlOS,WAAA,GAAc,KAkOvB,CAlO6B,WAkO7B,CAAA,GAAA;EAAuB,SAAA,CAAA,OAAA,EAjON,gBAiOM,CAAA,EAAA,IAAA;wBAhOH;;;iBAIP,iBAAA,gBACD,4BACA,0BACZ;iBA+Ga,cAAA,QACR,sBACE;iBAKM,gBAAA,QACR,sBACE;iBAKM,4BAAA,QACR,oBACA;;;;;;iBAyDQ,2BAAA,QACR,oBACA;iBA4BQ,qBAAA,QACR,MAAM,uCAEX"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { createStore } from "./create-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/store/typing-store.ts
|
|
4
|
+
const DEFAULT_TTL_MS = 6e3;
|
|
5
|
+
function makeKey(conversationId, actorType, actorId) {
|
|
6
|
+
return `${conversationId}:${actorType}:${actorId}`;
|
|
7
|
+
}
|
|
8
|
+
function removeEntry(state, conversationId, key) {
|
|
9
|
+
const existingConversation = state.conversations[conversationId];
|
|
10
|
+
if (!(existingConversation && key in existingConversation)) return state;
|
|
11
|
+
const { [key]: _removed,...rest } = existingConversation;
|
|
12
|
+
if (Object.keys(rest).length === 0) {
|
|
13
|
+
const nextConversations = { ...state.conversations };
|
|
14
|
+
delete nextConversations[conversationId];
|
|
15
|
+
return { conversations: nextConversations };
|
|
16
|
+
}
|
|
17
|
+
return { conversations: {
|
|
18
|
+
...state.conversations,
|
|
19
|
+
[conversationId]: rest
|
|
20
|
+
} };
|
|
21
|
+
}
|
|
22
|
+
function createTypingStore(initialState = { conversations: {} }, dependencies = {}) {
|
|
23
|
+
const { now = () => Date.now(), setTimeout: schedule = (callback, delay) => globalThis.setTimeout(callback, delay), clearTimeout: clearScheduled = (id) => globalThis.clearTimeout(id), defaultTtlMs = DEFAULT_TTL_MS } = dependencies;
|
|
24
|
+
const timers = /* @__PURE__ */ new Map();
|
|
25
|
+
const store = createStore({ conversations: { ...initialState.conversations } });
|
|
26
|
+
const clearTimer = (key) => {
|
|
27
|
+
const handle = timers.get(key);
|
|
28
|
+
if (!handle) return;
|
|
29
|
+
timers.delete(key);
|
|
30
|
+
clearScheduled(handle);
|
|
31
|
+
};
|
|
32
|
+
const scheduleRemoval = (key, options, ttl) => {
|
|
33
|
+
clearTimer(key);
|
|
34
|
+
const handle = schedule(() => {
|
|
35
|
+
timers.delete(key);
|
|
36
|
+
store.setState((state) => removeEntry(state, options.conversationId, key));
|
|
37
|
+
}, ttl);
|
|
38
|
+
timers.set(key, handle);
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
...store,
|
|
42
|
+
setTyping({ conversationId, actorType, actorId, isTyping, preview = null, ttlMs }) {
|
|
43
|
+
const key = makeKey(conversationId, actorType, actorId);
|
|
44
|
+
if (!isTyping) {
|
|
45
|
+
clearTimer(key);
|
|
46
|
+
store.setState((state) => removeEntry(state, conversationId, key));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const entry = {
|
|
50
|
+
actorType,
|
|
51
|
+
actorId,
|
|
52
|
+
preview: preview ?? null,
|
|
53
|
+
updatedAt: now()
|
|
54
|
+
};
|
|
55
|
+
store.setState((state) => {
|
|
56
|
+
const existingConversation = state.conversations[conversationId];
|
|
57
|
+
const nextConversation = {
|
|
58
|
+
...existingConversation ? { ...existingConversation } : {},
|
|
59
|
+
[key]: entry
|
|
60
|
+
};
|
|
61
|
+
return { conversations: {
|
|
62
|
+
...state.conversations,
|
|
63
|
+
[conversationId]: nextConversation
|
|
64
|
+
} };
|
|
65
|
+
});
|
|
66
|
+
scheduleRemoval(key, {
|
|
67
|
+
conversationId,
|
|
68
|
+
actorType,
|
|
69
|
+
actorId
|
|
70
|
+
}, ttlMs ?? defaultTtlMs);
|
|
71
|
+
},
|
|
72
|
+
removeTyping({ conversationId, actorType, actorId }) {
|
|
73
|
+
const key = makeKey(conversationId, actorType, actorId);
|
|
74
|
+
clearTimer(key);
|
|
75
|
+
store.setState((state) => removeEntry(state, conversationId, key));
|
|
76
|
+
},
|
|
77
|
+
clearConversation(conversationId) {
|
|
78
|
+
const conversation = store.getState().conversations[conversationId];
|
|
79
|
+
if (!conversation) return;
|
|
80
|
+
for (const key of Object.keys(conversation)) clearTimer(key);
|
|
81
|
+
store.setState((state) => {
|
|
82
|
+
if (!(conversationId in state.conversations)) return state;
|
|
83
|
+
const nextConversations = { ...state.conversations };
|
|
84
|
+
delete nextConversations[conversationId];
|
|
85
|
+
return { conversations: nextConversations };
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function setTypingState(store, options) {
|
|
91
|
+
store.setTyping(options);
|
|
92
|
+
}
|
|
93
|
+
function clearTypingState(store, options) {
|
|
94
|
+
store.removeTyping(options);
|
|
95
|
+
}
|
|
96
|
+
function applyConversationTypingEvent(store, event, options = {}) {
|
|
97
|
+
const { payload } = event;
|
|
98
|
+
let actorType = null;
|
|
99
|
+
let actorId = null;
|
|
100
|
+
if (payload.userId) {
|
|
101
|
+
actorType = "user";
|
|
102
|
+
actorId = payload.userId;
|
|
103
|
+
} else if (payload.visitorId) {
|
|
104
|
+
actorType = "visitor";
|
|
105
|
+
actorId = payload.visitorId;
|
|
106
|
+
} else if (payload.aiAgentId) {
|
|
107
|
+
actorType = "ai_agent";
|
|
108
|
+
actorId = payload.aiAgentId;
|
|
109
|
+
}
|
|
110
|
+
if (!(actorType && actorId)) return;
|
|
111
|
+
if (actorType === "visitor" && payload.visitorId && options.ignoreVisitorId && payload.visitorId === options.ignoreVisitorId || actorType === "user" && payload.userId && options.ignoreUserId && payload.userId === options.ignoreUserId || actorType === "ai_agent" && payload.aiAgentId && options.ignoreAiAgentId && payload.aiAgentId === options.ignoreAiAgentId) return;
|
|
112
|
+
const preview = actorType === "visitor" ? payload.visitorPreview ?? null : null;
|
|
113
|
+
setTypingState(store, {
|
|
114
|
+
conversationId: payload.conversationId,
|
|
115
|
+
actorType,
|
|
116
|
+
actorId,
|
|
117
|
+
isTyping: payload.isTyping,
|
|
118
|
+
preview,
|
|
119
|
+
ttlMs: options.ttlMs
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function clearTypingFromTimelineItem(store, event) {
|
|
123
|
+
const { item } = event.payload;
|
|
124
|
+
let actorType = null;
|
|
125
|
+
let actorId = null;
|
|
126
|
+
if (item.userId) {
|
|
127
|
+
actorType = "user";
|
|
128
|
+
actorId = item.userId;
|
|
129
|
+
} else if (item.visitorId) {
|
|
130
|
+
actorType = "visitor";
|
|
131
|
+
actorId = item.visitorId;
|
|
132
|
+
} else if (item.aiAgentId) {
|
|
133
|
+
actorType = "ai_agent";
|
|
134
|
+
actorId = item.aiAgentId;
|
|
135
|
+
}
|
|
136
|
+
if (!(actorType && actorId)) return;
|
|
137
|
+
clearTypingState(store, {
|
|
138
|
+
conversationId: item.conversationId,
|
|
139
|
+
actorType,
|
|
140
|
+
actorId
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function getConversationTyping(store, conversationId) {
|
|
144
|
+
return store.getState().conversations[conversationId];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
export { applyConversationTypingEvent, clearTypingFromTimelineItem, clearTypingState, createTypingStore, getConversationTyping, setTypingState };
|
|
149
|
+
//# sourceMappingURL=typing-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typing-store.js","names":["entry: TypingEntry","nextConversation: ConversationTypingState","actorType: TypingActorType | null","actorId: string | null"],"sources":["../../src/store/typing-store.ts"],"sourcesContent":["import type { RealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport { createStore, type Store } from \"./create-store\";\n\nexport type TypingActorType = \"visitor\" | \"user\" | \"ai_agent\";\n\nexport type TypingEntry = {\n\tactorType: TypingActorType;\n\tactorId: string;\n\tpreview: string | null;\n\tupdatedAt: number;\n};\n\nexport type ConversationTypingState = Record<string, TypingEntry>;\n\nexport type TypingState = {\n\tconversations: Record<string, ConversationTypingState>;\n};\n\nconst DEFAULT_TTL_MS = 6000;\n\nexport type TypingStoreDependencies = {\n\tnow?: () => number;\n\tsetTimeout?: (callback: () => void, delay: number) => unknown;\n\tclearTimeout?: (id: unknown) => void;\n\tdefaultTtlMs?: number;\n};\n\ntype TypingOptions = {\n\tconversationId: string;\n\tactorType: TypingActorType;\n\tactorId: string;\n};\n\ntype SetTypingOptions = TypingOptions & {\n\tisTyping: boolean;\n\tpreview?: string | null;\n\tttlMs?: number;\n};\n\nfunction makeKey(\n\tconversationId: string,\n\tactorType: TypingActorType,\n\tactorId: string\n): string {\n\treturn `${conversationId}:${actorType}:${actorId}`;\n}\n\nfunction removeEntry(\n\tstate: TypingState,\n\tconversationId: string,\n\tkey: string\n): TypingState {\n\tconst existingConversation = state.conversations[conversationId];\n\tif (!(existingConversation && key in existingConversation)) {\n\t\treturn state;\n\t}\n\n\tconst { [key]: _removed, ...rest } = existingConversation;\n\tif (Object.keys(rest).length === 0) {\n\t\tconst nextConversations = { ...state.conversations };\n\t\tdelete nextConversations[conversationId];\n\t\treturn { conversations: nextConversations } satisfies TypingState;\n\t}\n\n\treturn {\n\t\tconversations: {\n\t\t\t...state.conversations,\n\t\t\t[conversationId]: rest,\n\t\t},\n\t} satisfies TypingState;\n}\n\nexport type TypingStore = Store<TypingState> & {\n\tsetTyping(options: SetTypingOptions): void;\n\tremoveTyping(options: TypingOptions): void;\n\tclearConversation(conversationId: string): void;\n};\n\nexport function createTypingStore(\n\tinitialState: TypingState = { conversations: {} },\n\tdependencies: TypingStoreDependencies = {}\n): TypingStore {\n\tconst {\n\t\tnow = () => Date.now(),\n\t\tsetTimeout: schedule = (callback, delay) =>\n\t\t\tglobalThis.setTimeout(callback, delay),\n\t\tclearTimeout: clearScheduled = (id) =>\n\t\t\tglobalThis.clearTimeout(id as ReturnType<typeof globalThis.setTimeout>),\n\t\tdefaultTtlMs = DEFAULT_TTL_MS,\n\t} = dependencies;\n\n\tconst timers = new Map<string, unknown>();\n\tconst store = createStore<TypingState>({\n\t\tconversations: { ...initialState.conversations },\n\t});\n\n\tconst clearTimer = (key: string) => {\n\t\tconst handle = timers.get(key);\n\t\tif (!handle) {\n\t\t\treturn;\n\t\t}\n\t\ttimers.delete(key);\n\t\tclearScheduled(handle);\n\t};\n\n\tconst scheduleRemoval = (\n\t\tkey: string,\n\t\toptions: TypingOptions,\n\t\tttl: number\n\t) => {\n\t\tclearTimer(key);\n\t\tconst handle = schedule(() => {\n\t\t\ttimers.delete(key);\n\t\t\tstore.setState((state) =>\n\t\t\t\tremoveEntry(state, options.conversationId, key)\n\t\t\t);\n\t\t}, ttl);\n\t\ttimers.set(key, handle);\n\t};\n\n\treturn {\n\t\t...store,\n\t\tsetTyping({\n\t\t\tconversationId,\n\t\t\tactorType,\n\t\t\tactorId,\n\t\t\tisTyping,\n\t\t\tpreview = null,\n\t\t\tttlMs,\n\t\t}) {\n\t\t\tconst key = makeKey(conversationId, actorType, actorId);\n\n\t\t\tif (!isTyping) {\n\t\t\t\tclearTimer(key);\n\t\t\t\tstore.setState((state) => removeEntry(state, conversationId, key));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst entry: TypingEntry = {\n\t\t\t\tactorType,\n\t\t\t\tactorId,\n\t\t\t\tpreview: preview ?? null,\n\t\t\t\tupdatedAt: now(),\n\t\t\t};\n\n\t\t\tstore.setState((state) => {\n\t\t\t\tconst existingConversation = state.conversations[conversationId];\n\n\t\t\t\tconst nextConversation: ConversationTypingState = {\n\t\t\t\t\t...(existingConversation ? { ...existingConversation } : {}),\n\t\t\t\t\t[key]: entry,\n\t\t\t\t};\n\n\t\t\t\treturn {\n\t\t\t\t\tconversations: {\n\t\t\t\t\t\t...state.conversations,\n\t\t\t\t\t\t[conversationId]: nextConversation,\n\t\t\t\t\t},\n\t\t\t\t} satisfies TypingState;\n\t\t\t});\n\n\t\t\tconst timeoutMs = ttlMs ?? defaultTtlMs;\n\t\t\tscheduleRemoval(key, { conversationId, actorType, actorId }, timeoutMs);\n\t\t},\n\t\tremoveTyping({ conversationId, actorType, actorId }) {\n\t\t\tconst key = makeKey(conversationId, actorType, actorId);\n\t\t\tclearTimer(key);\n\t\t\tstore.setState((state) => removeEntry(state, conversationId, key));\n\t\t},\n\t\tclearConversation(conversationId) {\n\t\t\tconst conversation = store.getState().conversations[conversationId];\n\t\t\tif (!conversation) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const key of Object.keys(conversation)) {\n\t\t\t\tclearTimer(key);\n\t\t\t}\n\n\t\t\tstore.setState((state) => {\n\t\t\t\tif (!(conversationId in state.conversations)) {\n\t\t\t\t\treturn state;\n\t\t\t\t}\n\n\t\t\t\tconst nextConversations = { ...state.conversations };\n\t\t\t\tdelete nextConversations[conversationId];\n\t\t\t\treturn { conversations: nextConversations } satisfies TypingState;\n\t\t\t});\n\t\t},\n\t} satisfies TypingStore;\n}\n\nexport function setTypingState(\n\tstore: TypingStore,\n\toptions: SetTypingOptions\n): void {\n\tstore.setTyping(options);\n}\n\nexport function clearTypingState(\n\tstore: TypingStore,\n\toptions: TypingOptions\n): void {\n\tstore.removeTyping(options);\n}\n\nexport function applyConversationTypingEvent(\n\tstore: TypingStore,\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): void {\n\tconst { payload } = event;\n\tlet actorType: TypingActorType | null = null;\n\tlet actorId: string | null = null;\n\n\tif (payload.userId) {\n\t\tactorType = \"user\";\n\t\tactorId = payload.userId;\n\t} else if (payload.visitorId) {\n\t\tactorType = \"visitor\";\n\t\tactorId = payload.visitorId;\n\t} else if (payload.aiAgentId) {\n\t\tactorType = \"ai_agent\";\n\t\tactorId = payload.aiAgentId;\n\t}\n\n\tif (!(actorType && actorId)) {\n\t\treturn;\n\t}\n\n\tif (\n\t\t(actorType === \"visitor\" &&\n\t\t\tpayload.visitorId &&\n\t\t\toptions.ignoreVisitorId &&\n\t\t\tpayload.visitorId === options.ignoreVisitorId) ||\n\t\t(actorType === \"user\" &&\n\t\t\tpayload.userId &&\n\t\t\toptions.ignoreUserId &&\n\t\t\tpayload.userId === options.ignoreUserId) ||\n\t\t(actorType === \"ai_agent\" &&\n\t\t\tpayload.aiAgentId &&\n\t\t\toptions.ignoreAiAgentId &&\n\t\t\tpayload.aiAgentId === options.ignoreAiAgentId)\n\t) {\n\t\treturn;\n\t}\n\n\tconst preview =\n\t\tactorType === \"visitor\" ? (payload.visitorPreview ?? null) : null;\n\n\tsetTypingState(store, {\n\t\tconversationId: payload.conversationId,\n\t\tactorType,\n\t\tactorId,\n\t\tisTyping: payload.isTyping,\n\t\tpreview,\n\t\tttlMs: options.ttlMs,\n\t});\n}\n\nexport function clearTypingFromTimelineItem(\n\tstore: TypingStore,\n\tevent: RealtimeEvent<\"timelineItemCreated\">\n): void {\n\tconst { item } = event.payload;\n\tlet actorType: TypingActorType | null = null;\n\tlet actorId: string | null = null;\n\n\tif (item.userId) {\n\t\tactorType = \"user\";\n\t\tactorId = item.userId;\n\t} else if (item.visitorId) {\n\t\tactorType = \"visitor\";\n\t\tactorId = item.visitorId;\n\t} else if (item.aiAgentId) {\n\t\tactorType = \"ai_agent\";\n\t\tactorId = item.aiAgentId;\n\t}\n\n\tif (!(actorType && actorId)) {\n\t\treturn;\n\t}\n\n\tclearTypingState(store, {\n\t\tconversationId: item.conversationId,\n\t\tactorType,\n\t\tactorId,\n\t});\n}\n\nexport function getConversationTyping(\n\tstore: Store<TypingState>,\n\tconversationId: string\n): ConversationTypingState | undefined {\n\treturn store.getState().conversations[conversationId];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Store } from "./create-store.js";
|
|
2
|
+
import { PublicWebsiteResponse } from "@cossistant/types";
|
|
3
|
+
|
|
4
|
+
//#region src/store/website-store.d.ts
|
|
5
|
+
type WebsiteStatus = "idle" | "loading" | "success" | "error";
|
|
6
|
+
type WebsiteError = {
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
type WebsiteState = {
|
|
10
|
+
website: PublicWebsiteResponse | null;
|
|
11
|
+
status: WebsiteStatus;
|
|
12
|
+
error: WebsiteError | null;
|
|
13
|
+
};
|
|
14
|
+
type WebsiteStore = Store<WebsiteState> & {
|
|
15
|
+
setLoading(): void;
|
|
16
|
+
setWebsite(website: PublicWebsiteResponse): void;
|
|
17
|
+
setError(error: unknown): void;
|
|
18
|
+
reset(): void;
|
|
19
|
+
};
|
|
20
|
+
declare function createWebsiteStore(initialState?: WebsiteState): WebsiteStore;
|
|
21
|
+
declare function getWebsiteState(store: Store<WebsiteState>): WebsiteState;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { WebsiteError, WebsiteState, WebsiteStatus, WebsiteStore, createWebsiteStore, getWebsiteState };
|
|
24
|
+
//# sourceMappingURL=website-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"website-store.d.ts","names":[],"sources":["../../src/store/website-store.ts"],"sourcesContent":[],"mappings":";;;;KAGY,aAAA;KAEA,YAAA;EAFA,OAAA,EAAA,MAAA;AAEZ,CAAA;AAIY,KAAA,YAAA,GAAY;EACd,OAAA,EAAA,qBAAA,GAAA,IAAA;EACD,MAAA,EAAA,aAAA;EACD,KAAA,EAAA,YAAA,GAAA,IAAA;CAAY;AA0BR,KAAA,YAAA,GAAe,KAAH,CAAS,YAAT,CAAA,GAAA;EAAS,UAAA,EAAA,EAAA,IAAA;EAAN,UAAA,CAAA,OAAA,EAEN,qBAFM,CAAA,EAAA,IAAA;EAEN,QAAA,CAAA,KAAA,EAAA,OAAA,CAAA,EAAA,IAAA;EAAqB,KAAA,EAAA,EAAA,IAAA;AAK1C,CAAA;AA6DgB,iBA7DA,kBAAA,CA6De,YAAA,CAAA,EA5DhB,YA4DgB,CAAA,EA3D5B,YA2D4B;AAAc,iBAA7B,eAAA,CAA6B,KAAA,EAAN,KAAM,CAAA,YAAA,CAAA,CAAA,EAAgB,YAAhB"}
|