@antzsoft/chat-core 1.0.2 → 1.0.4
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/README.md +574 -57
- package/dist/chat.store-PY3YVYGN.js +7 -0
- package/dist/chat.store-PY3YVYGN.js.map +1 -0
- package/dist/chunk-TB52RCSF.js +54 -0
- package/dist/chunk-TB52RCSF.js.map +1 -0
- package/dist/index.cjs +193 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +171 -15
- package/dist/index.d.ts +171 -15
- package/dist/index.js +128 -55
- package/dist/index.js.map +1 -1
- package/docs/integration-guide.html +2324 -0
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/stores/chat.store.ts
|
|
2
|
+
import { create } from "zustand";
|
|
3
|
+
var useChatStore = create((set) => ({
|
|
4
|
+
activeConversationId: null,
|
|
5
|
+
pendingTarget: null,
|
|
6
|
+
typingUsers: {},
|
|
7
|
+
onlineUsers: [],
|
|
8
|
+
lastRead: {},
|
|
9
|
+
lastSeen: {},
|
|
10
|
+
replyingTo: null,
|
|
11
|
+
editingMessage: null,
|
|
12
|
+
isSidebarOpen: true,
|
|
13
|
+
isGroupInfoOpen: false,
|
|
14
|
+
isStarredPanelOpen: false,
|
|
15
|
+
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null }),
|
|
16
|
+
setPendingTarget: (target) => set({ pendingTarget: target }),
|
|
17
|
+
addTypingUser: (conversationId, user) => set((state) => {
|
|
18
|
+
const existing = state.typingUsers[conversationId] ?? [];
|
|
19
|
+
const deduped = existing.filter((u) => u.userId !== user.userId);
|
|
20
|
+
return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };
|
|
21
|
+
}),
|
|
22
|
+
removeTypingUser: (conversationId, userId) => set((state) => ({
|
|
23
|
+
typingUsers: {
|
|
24
|
+
...state.typingUsers,
|
|
25
|
+
[conversationId]: (state.typingUsers[conversationId] ?? []).filter(
|
|
26
|
+
(u) => u.userId !== userId
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
})),
|
|
30
|
+
setUserOnline: (userId) => set((state) => ({
|
|
31
|
+
onlineUsers: state.onlineUsers.includes(userId) ? state.onlineUsers : [...state.onlineUsers, userId]
|
|
32
|
+
})),
|
|
33
|
+
setUserOffline: (userId) => set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),
|
|
34
|
+
setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),
|
|
35
|
+
setLastRead: (conversationId, messageId, readAt) => set((state) => ({
|
|
36
|
+
lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } }
|
|
37
|
+
})),
|
|
38
|
+
setLastSeen: (userId, lastSeenAt) => set((state) => ({
|
|
39
|
+
lastSeen: { ...state.lastSeen, [userId]: lastSeenAt }
|
|
40
|
+
})),
|
|
41
|
+
setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
|
|
42
|
+
setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
|
|
43
|
+
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
|
|
44
|
+
setSidebarOpen: (open) => set({ isSidebarOpen: open }),
|
|
45
|
+
toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),
|
|
46
|
+
setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),
|
|
47
|
+
toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),
|
|
48
|
+
setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open })
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
useChatStore
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=chunk-TB52RCSF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores/chat.store.ts"],"sourcesContent":["import { create } from 'zustand';\nimport type { Message } from '../types/index.js';\n\ninterface TypingUser {\n userId: string;\n displayName: string;\n avatarUrl?: string;\n}\n\nexport interface LastReadEntry {\n messageId: string;\n readAt: string;\n}\n\ninterface ChatState {\n activeConversationId: string | null;\n pendingTarget: { conversationId: string; messageId: string } | null;\n typingUsers: Record<string, TypingUser[]>;\n onlineUsers: string[];\n /** keyed by conversationId — current user's last read pointer per conversation */\n lastRead: Record<string, LastReadEntry>;\n /** keyed by userId — last seen timestamp for each user */\n lastSeen: Record<string, string>;\n replyingTo: Message | null;\n editingMessage: Message | null;\n isSidebarOpen: boolean;\n isGroupInfoOpen: boolean;\n isStarredPanelOpen: boolean;\n\n setActiveConversation: (id: string | null) => void;\n setPendingTarget: (target: { conversationId: string; messageId: string } | null) => void;\n addTypingUser: (conversationId: string, user: TypingUser) => void;\n removeTypingUser: (conversationId: string, userId: string) => void;\n setUserOnline: (userId: string) => void;\n setUserOffline: (userId: string) => void;\n setOnlineUsers: (userIds: string[]) => void;\n setLastRead: (conversationId: string, messageId: string, readAt: string) => void;\n setLastSeen: (userId: string, lastSeenAt: string) => void;\n setReplyingTo: (message: Message | null) => void;\n setEditingMessage: (message: Message | null) => void;\n toggleSidebar: () => void;\n setSidebarOpen: (open: boolean) => void;\n toggleGroupInfo: () => void;\n setGroupInfoOpen: (open: boolean) => void;\n toggleStarredPanel: () => void;\n setStarredPanelOpen: (open: boolean) => void;\n}\n\nexport const useChatStore = create<ChatState>((set) => ({\n activeConversationId: null,\n pendingTarget: null,\n typingUsers: {},\n onlineUsers: [],\n lastRead: {},\n lastSeen: {},\n replyingTo: null,\n editingMessage: null,\n isSidebarOpen: true,\n isGroupInfoOpen: false,\n isStarredPanelOpen: false,\n\n setActiveConversation: (id) =>\n set({ activeConversationId: id, replyingTo: null, editingMessage: null }),\n\n setPendingTarget: (target) => set({ pendingTarget: target }),\n\n addTypingUser: (conversationId, user) =>\n set((state) => {\n const existing = state.typingUsers[conversationId] ?? [];\n const deduped = existing.filter((u) => u.userId !== user.userId);\n return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };\n }),\n\n removeTypingUser: (conversationId, userId) =>\n set((state) => ({\n typingUsers: {\n ...state.typingUsers,\n [conversationId]: (state.typingUsers[conversationId] ?? []).filter(\n (u) => u.userId !== userId,\n ),\n },\n })),\n\n setUserOnline: (userId) =>\n set((state) => ({\n onlineUsers: state.onlineUsers.includes(userId)\n ? state.onlineUsers\n : [...state.onlineUsers, userId],\n })),\n\n setUserOffline: (userId) =>\n set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),\n\n setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),\n\n setLastRead: (conversationId, messageId, readAt) =>\n set((state) => ({\n lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } },\n })),\n\n setLastSeen: (userId, lastSeenAt) =>\n set((state) => ({\n lastSeen: { ...state.lastSeen, [userId]: lastSeenAt },\n })),\n\n setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),\n\n setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),\n\n toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),\n setSidebarOpen: (open) => set({ isSidebarOpen: open }),\n\n toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),\n setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),\n\n toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),\n setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open }),\n}));\n"],"mappings":";AAAA,SAAS,cAAc;AAgDhB,IAAM,eAAe,OAAkB,CAAC,SAAS;AAAA,EACtD,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,aAAa,CAAC;AAAA,EACd,aAAa,CAAC;AAAA,EACd,UAAU,CAAC;AAAA,EACX,UAAU,CAAC;AAAA,EACX,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EAEpB,uBAAuB,CAAC,OACtB,IAAI,EAAE,sBAAsB,IAAI,YAAY,MAAM,gBAAgB,KAAK,CAAC;AAAA,EAE1E,kBAAkB,CAAC,WAAW,IAAI,EAAE,eAAe,OAAO,CAAC;AAAA,EAE3D,eAAe,CAAC,gBAAgB,SAC9B,IAAI,CAAC,UAAU;AACb,UAAM,WAAW,MAAM,YAAY,cAAc,KAAK,CAAC;AACvD,UAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,MAAM;AAC/D,WAAO,EAAE,aAAa,EAAE,GAAG,MAAM,aAAa,CAAC,cAAc,GAAG,CAAC,GAAG,SAAS,IAAI,EAAE,EAAE;AAAA,EACvF,CAAC;AAAA,EAEH,kBAAkB,CAAC,gBAAgB,WACjC,IAAI,CAAC,WAAW;AAAA,IACd,aAAa;AAAA,MACX,GAAG,MAAM;AAAA,MACT,CAAC,cAAc,IAAI,MAAM,YAAY,cAAc,KAAK,CAAC,GAAG;AAAA,QAC1D,CAAC,MAAM,EAAE,WAAW;AAAA,MACtB;AAAA,IACF;AAAA,EACF,EAAE;AAAA,EAEJ,eAAe,CAAC,WACd,IAAI,CAAC,WAAW;AAAA,IACd,aAAa,MAAM,YAAY,SAAS,MAAM,IAC1C,MAAM,cACN,CAAC,GAAG,MAAM,aAAa,MAAM;AAAA,EACnC,EAAE;AAAA,EAEJ,gBAAgB,CAAC,WACf,IAAI,CAAC,WAAW,EAAE,aAAa,MAAM,YAAY,OAAO,CAAC,OAAO,OAAO,MAAM,EAAE,EAAE;AAAA,EAEnF,gBAAgB,CAAC,YAAY,IAAI,EAAE,aAAa,QAAQ,CAAC;AAAA,EAEzD,aAAa,CAAC,gBAAgB,WAAW,WACvC,IAAI,CAAC,WAAW;AAAA,IACd,UAAU,EAAE,GAAG,MAAM,UAAU,CAAC,cAAc,GAAG,EAAE,WAAW,OAAO,EAAE;AAAA,EACzE,EAAE;AAAA,EAEJ,aAAa,CAAC,QAAQ,eACpB,IAAI,CAAC,WAAW;AAAA,IACd,UAAU,EAAE,GAAG,MAAM,UAAU,CAAC,MAAM,GAAG,WAAW;AAAA,EACtD,EAAE;AAAA,EAEJ,eAAe,CAAC,YAAY,IAAI,EAAE,YAAY,SAAS,gBAAgB,KAAK,CAAC;AAAA,EAE7E,mBAAmB,CAAC,YAAY,IAAI,EAAE,gBAAgB,SAAS,YAAY,KAAK,CAAC;AAAA,EAEjF,eAAe,MAAM,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,MAAM,cAAc,EAAE;AAAA,EAC7E,gBAAgB,CAAC,SAAS,IAAI,EAAE,eAAe,KAAK,CAAC;AAAA,EAErD,iBAAiB,MAAM,IAAI,CAAC,WAAW,EAAE,iBAAiB,CAAC,MAAM,gBAAgB,EAAE;AAAA,EACnF,kBAAkB,CAAC,SAAS,IAAI,EAAE,iBAAiB,KAAK,CAAC;AAAA,EAEzD,oBAAoB,MAAM,IAAI,CAAC,WAAW,EAAE,oBAAoB,CAAC,MAAM,mBAAmB,EAAE;AAAA,EAC5F,qBAAqB,CAAC,SAAS,IAAI,EAAE,oBAAoB,KAAK,CAAC;AACjE,EAAE;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,66 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/stores/chat.store.ts
|
|
34
|
+
var chat_store_exports = {};
|
|
35
|
+
__export(chat_store_exports, {
|
|
36
|
+
useChatStore: () => useChatStore
|
|
37
|
+
});
|
|
38
|
+
var import_zustand, useChatStore;
|
|
39
|
+
var init_chat_store = __esm({
|
|
40
|
+
"src/stores/chat.store.ts"() {
|
|
41
|
+
"use strict";
|
|
42
|
+
import_zustand = require("zustand");
|
|
43
|
+
useChatStore = (0, import_zustand.create)((set) => ({
|
|
44
|
+
activeConversationId: null,
|
|
45
|
+
pendingTarget: null,
|
|
46
|
+
typingUsers: {},
|
|
47
|
+
onlineUsers: [],
|
|
48
|
+
lastRead: {},
|
|
49
|
+
lastSeen: {},
|
|
50
|
+
replyingTo: null,
|
|
51
|
+
editingMessage: null,
|
|
52
|
+
isSidebarOpen: true,
|
|
53
|
+
isGroupInfoOpen: false,
|
|
54
|
+
isStarredPanelOpen: false,
|
|
55
|
+
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null }),
|
|
56
|
+
setPendingTarget: (target) => set({ pendingTarget: target }),
|
|
57
|
+
addTypingUser: (conversationId, user) => set((state) => {
|
|
58
|
+
const existing = state.typingUsers[conversationId] ?? [];
|
|
59
|
+
const deduped = existing.filter((u) => u.userId !== user.userId);
|
|
60
|
+
return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };
|
|
61
|
+
}),
|
|
62
|
+
removeTypingUser: (conversationId, userId) => set((state) => ({
|
|
63
|
+
typingUsers: {
|
|
64
|
+
...state.typingUsers,
|
|
65
|
+
[conversationId]: (state.typingUsers[conversationId] ?? []).filter(
|
|
66
|
+
(u) => u.userId !== userId
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
})),
|
|
70
|
+
setUserOnline: (userId) => set((state) => ({
|
|
71
|
+
onlineUsers: state.onlineUsers.includes(userId) ? state.onlineUsers : [...state.onlineUsers, userId]
|
|
72
|
+
})),
|
|
73
|
+
setUserOffline: (userId) => set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),
|
|
74
|
+
setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),
|
|
75
|
+
setLastRead: (conversationId, messageId, readAt) => set((state) => ({
|
|
76
|
+
lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } }
|
|
77
|
+
})),
|
|
78
|
+
setLastSeen: (userId, lastSeenAt) => set((state) => ({
|
|
79
|
+
lastSeen: { ...state.lastSeen, [userId]: lastSeenAt }
|
|
80
|
+
})),
|
|
81
|
+
setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
|
|
82
|
+
setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
|
|
83
|
+
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
|
|
84
|
+
setSidebarOpen: (open) => set({ isSidebarOpen: open }),
|
|
85
|
+
toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),
|
|
86
|
+
setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),
|
|
87
|
+
toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),
|
|
88
|
+
setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open })
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
30
93
|
// src/index.ts
|
|
31
94
|
var src_exports = {};
|
|
32
95
|
__export(src_exports, {
|
|
@@ -55,7 +118,8 @@ __export(src_exports, {
|
|
|
55
118
|
storageApi: () => storageApi,
|
|
56
119
|
tryGetSocket: () => tryGetSocket,
|
|
57
120
|
uploadBatch: () => uploadBatch,
|
|
58
|
-
useChatStore: () => useChatStore
|
|
121
|
+
useChatStore: () => useChatStore,
|
|
122
|
+
usersApi: () => usersApi
|
|
59
123
|
});
|
|
60
124
|
module.exports = __toCommonJS(src_exports);
|
|
61
125
|
|
|
@@ -104,7 +168,10 @@ function resolveConfig(config) {
|
|
|
104
168
|
onProgress: config.upload?.onProgress
|
|
105
169
|
},
|
|
106
170
|
platformUploadFn: config.platformUploadFn,
|
|
107
|
-
persistStorage: config.persistStorage
|
|
171
|
+
persistStorage: config.persistStorage,
|
|
172
|
+
messagePageSize: config.messagePageSize ?? 40,
|
|
173
|
+
starredMessagePageSize: config.starredMessagePageSize ?? 30,
|
|
174
|
+
searchPageSize: config.searchPageSize ?? 50
|
|
108
175
|
};
|
|
109
176
|
}
|
|
110
177
|
|
|
@@ -238,9 +305,14 @@ var authApi = {
|
|
|
238
305
|
// src/api/messages.ts
|
|
239
306
|
var messagesApi = {
|
|
240
307
|
async list(conversationId, params = {}) {
|
|
308
|
+
const { cursor, direction, ...rest } = params;
|
|
309
|
+
const serverParams = { ...rest };
|
|
310
|
+
if (cursor) {
|
|
311
|
+
serverParams[direction === "after" ? "after" : "before"] = cursor;
|
|
312
|
+
}
|
|
241
313
|
const { data } = await getApiClient().get(
|
|
242
314
|
`/conversations/${conversationId}/messages`,
|
|
243
|
-
{ params }
|
|
315
|
+
{ params: serverParams }
|
|
244
316
|
);
|
|
245
317
|
return data;
|
|
246
318
|
},
|
|
@@ -289,6 +361,12 @@ var messagesApi = {
|
|
|
289
361
|
const { data } = await getApiClient().get("/messages/search", { params });
|
|
290
362
|
return data;
|
|
291
363
|
},
|
|
364
|
+
async getLastRead(conversationId) {
|
|
365
|
+
const { data } = await getApiClient().get(
|
|
366
|
+
`/conversations/${conversationId}/read-receipt`
|
|
367
|
+
);
|
|
368
|
+
return data;
|
|
369
|
+
},
|
|
292
370
|
async markAsRead(conversationId, messageId) {
|
|
293
371
|
await getApiClient().post(`/conversations/${conversationId}/read`, messageId ? { messageId } : {});
|
|
294
372
|
},
|
|
@@ -417,9 +495,45 @@ var conversationsApi = {
|
|
|
417
495
|
const { data } = await getApiClient().get(`/conversations/${conversationId}/participants`);
|
|
418
496
|
return data;
|
|
419
497
|
},
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
498
|
+
/**
|
|
499
|
+
* Get unread message count for a single conversation.
|
|
500
|
+
* Use this after app foreground or socket reconnect to refresh a specific count.
|
|
501
|
+
*/
|
|
502
|
+
async getUnreadCount(conversationId) {
|
|
503
|
+
const { data } = await getApiClient().get(
|
|
504
|
+
`/conversations/${conversationId}/unread`
|
|
505
|
+
);
|
|
506
|
+
return data;
|
|
507
|
+
},
|
|
508
|
+
/**
|
|
509
|
+
* Get total unread count across all conversations + per-conversation breakdown.
|
|
510
|
+
* Use on app cold start, foreground resume, or after socket reconnect.
|
|
511
|
+
* The socket keeps counts live while connected — this is the source of truth
|
|
512
|
+
* when the socket was down.
|
|
513
|
+
*/
|
|
514
|
+
async getUnreadSummary() {
|
|
515
|
+
const { data } = await getApiClient().get("/conversations/unread");
|
|
516
|
+
return data;
|
|
517
|
+
},
|
|
518
|
+
/**
|
|
519
|
+
* Upload or replace the group icon (admin only).
|
|
520
|
+
* Accepts a File (web) or { uri, name, type } object (React Native).
|
|
521
|
+
* The server stores the image in its own storage, deletes the previous icon,
|
|
522
|
+
* and returns a fresh signed iconUrl on every subsequent response.
|
|
523
|
+
*/
|
|
524
|
+
async uploadIcon(conversationId, file) {
|
|
525
|
+
const formData = new FormData();
|
|
526
|
+
if (file instanceof File) {
|
|
527
|
+
formData.append("icon", file);
|
|
528
|
+
} else {
|
|
529
|
+
formData.append("icon", { uri: file.uri, name: file.name, type: file.type });
|
|
530
|
+
}
|
|
531
|
+
const { data } = await getApiClient().put(
|
|
532
|
+
`/conversations/${conversationId}/icon`,
|
|
533
|
+
formData,
|
|
534
|
+
{ headers: { "Content-Type": "multipart/form-data" } }
|
|
535
|
+
);
|
|
536
|
+
return normalizeConversation(data);
|
|
423
537
|
}
|
|
424
538
|
};
|
|
425
539
|
|
|
@@ -524,6 +638,44 @@ var devicesApi = {
|
|
|
524
638
|
}
|
|
525
639
|
};
|
|
526
640
|
|
|
641
|
+
// src/api/users.ts
|
|
642
|
+
var usersApi = {
|
|
643
|
+
async list(params = {}) {
|
|
644
|
+
const { data } = await getApiClient().get("/users", { params });
|
|
645
|
+
return data;
|
|
646
|
+
},
|
|
647
|
+
async getById(userId) {
|
|
648
|
+
const { data } = await getApiClient().get(`/users/${userId}`);
|
|
649
|
+
return data;
|
|
650
|
+
},
|
|
651
|
+
async getLastSeen(userId) {
|
|
652
|
+
const { data } = await getApiClient().get(`/users/${userId}`);
|
|
653
|
+
return { lastSeenAt: data.lastSeenAt ?? null };
|
|
654
|
+
},
|
|
655
|
+
/**
|
|
656
|
+
* Update notification preferences for the current user.
|
|
657
|
+
* Partial update — only send fields you want to change.
|
|
658
|
+
* A prefs record is automatically created with defaults when a device
|
|
659
|
+
* token is first registered, so this never fails with "not found".
|
|
660
|
+
*/
|
|
661
|
+
async updatePreferences(prefs) {
|
|
662
|
+
const { data } = await getApiClient().put("/users/me/preferences", prefs);
|
|
663
|
+
return data;
|
|
664
|
+
},
|
|
665
|
+
/**
|
|
666
|
+
* Fetch current notification preferences for the current user.
|
|
667
|
+
* Returns null if no prefs record exists yet (all defaults apply).
|
|
668
|
+
*/
|
|
669
|
+
async getPreferences() {
|
|
670
|
+
try {
|
|
671
|
+
const { data } = await getApiClient().get("/users/me/preferences");
|
|
672
|
+
return data;
|
|
673
|
+
} catch {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
527
679
|
// src/socket/socket.ts
|
|
528
680
|
var import_socket = require("socket.io-client");
|
|
529
681
|
var _socket = null;
|
|
@@ -550,17 +702,17 @@ function onSocketStatus(listener) {
|
|
|
550
702
|
_statusListeners.add(listener);
|
|
551
703
|
return () => _statusListeners.delete(listener);
|
|
552
704
|
}
|
|
553
|
-
async function connectSocket(config, getToken
|
|
554
|
-
if (_socket
|
|
705
|
+
async function connectSocket(config, getToken) {
|
|
706
|
+
if (_socket && !_socket.disconnected) return _socket;
|
|
555
707
|
_getToken = getToken;
|
|
556
|
-
_userId = userId;
|
|
557
|
-
_tenantId = tenantId;
|
|
708
|
+
_userId = config.userId;
|
|
709
|
+
_tenantId = config.tenantId;
|
|
558
710
|
const token = getToken();
|
|
559
711
|
_socket = (0, import_socket.io)(`${config.socketOrigin}/chat`, {
|
|
560
712
|
auth: {
|
|
561
713
|
token: token ? `Bearer ${token}` : "",
|
|
562
|
-
...userId && { userId },
|
|
563
|
-
...tenantId && { tenantId },
|
|
714
|
+
...config.userId && { userId: config.userId },
|
|
715
|
+
...config.tenantId && { tenantId: config.tenantId },
|
|
564
716
|
...config.avatar?.url && { avatarUrl: config.avatar.url },
|
|
565
717
|
...config.avatar?.base64 && { avatarBase64: config.avatar.base64 }
|
|
566
718
|
},
|
|
@@ -578,9 +730,30 @@ async function connectSocket(config, getToken, userId, tenantId) {
|
|
|
578
730
|
setStatus("connecting");
|
|
579
731
|
_socket.on("connect", () => setStatus("connected"));
|
|
580
732
|
_socket.on("disconnect", () => setStatus("disconnected"));
|
|
581
|
-
_socket.on("connect_error", () =>
|
|
733
|
+
_socket.on("connect_error", (err) => {
|
|
734
|
+
console.error("[AntzChat] Socket connect_error:", err?.message, err?.data);
|
|
735
|
+
setStatus("error");
|
|
736
|
+
});
|
|
582
737
|
_socket.on("reconnecting", () => setStatus("reconnecting"));
|
|
583
738
|
_socket.on("reconnect", () => setStatus("connected"));
|
|
739
|
+
_socket.on("read_receipt", (event) => {
|
|
740
|
+
Promise.resolve().then(() => (init_chat_store(), chat_store_exports)).then(({ useChatStore: useChatStore2 }) => {
|
|
741
|
+
useChatStore2.getState().setLastRead(event.conversationId, event.messageId, event.readAt);
|
|
742
|
+
});
|
|
743
|
+
});
|
|
744
|
+
_socket.on("user_online", (event) => {
|
|
745
|
+
Promise.resolve().then(() => (init_chat_store(), chat_store_exports)).then(({ useChatStore: useChatStore2 }) => {
|
|
746
|
+
const store = useChatStore2.getState();
|
|
747
|
+
store.setUserOnline(event.userId);
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
_socket.on("user_offline", (event) => {
|
|
751
|
+
Promise.resolve().then(() => (init_chat_store(), chat_store_exports)).then(({ useChatStore: useChatStore2 }) => {
|
|
752
|
+
const store = useChatStore2.getState();
|
|
753
|
+
store.setUserOffline(event.userId);
|
|
754
|
+
if (event.lastSeenAt) store.setLastSeen(event.userId, event.lastSeenAt);
|
|
755
|
+
});
|
|
756
|
+
});
|
|
584
757
|
return _socket;
|
|
585
758
|
}
|
|
586
759
|
function disconnectSocket() {
|
|
@@ -695,12 +868,12 @@ var socketEmit = {
|
|
|
695
868
|
};
|
|
696
869
|
|
|
697
870
|
// src/stores/auth.store.ts
|
|
698
|
-
var
|
|
871
|
+
var import_zustand2 = require("zustand");
|
|
699
872
|
var import_middleware = require("zustand/middleware");
|
|
700
873
|
function createAuthStore(storage) {
|
|
701
874
|
if (!storage) throw new Error("[AntzChat] createAuthStore requires a valid PersistStorage \u2014 received undefined. Make sure the SDK config is fully resolved before initializing the store.");
|
|
702
875
|
const ref = { store: null };
|
|
703
|
-
const store = (0,
|
|
876
|
+
const store = (0, import_zustand2.create)()(
|
|
704
877
|
(0, import_middleware.persist)(
|
|
705
878
|
(set) => ({
|
|
706
879
|
user: null,
|
|
@@ -781,47 +954,8 @@ function resetAuthStore() {
|
|
|
781
954
|
_authStore = null;
|
|
782
955
|
}
|
|
783
956
|
|
|
784
|
-
// src/
|
|
785
|
-
|
|
786
|
-
var useChatStore = (0, import_zustand2.create)((set) => ({
|
|
787
|
-
activeConversationId: null,
|
|
788
|
-
pendingTarget: null,
|
|
789
|
-
typingUsers: {},
|
|
790
|
-
onlineUsers: [],
|
|
791
|
-
replyingTo: null,
|
|
792
|
-
editingMessage: null,
|
|
793
|
-
isSidebarOpen: true,
|
|
794
|
-
isGroupInfoOpen: false,
|
|
795
|
-
isStarredPanelOpen: false,
|
|
796
|
-
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null }),
|
|
797
|
-
setPendingTarget: (target) => set({ pendingTarget: target }),
|
|
798
|
-
addTypingUser: (conversationId, user) => set((state) => {
|
|
799
|
-
const existing = state.typingUsers[conversationId] ?? [];
|
|
800
|
-
const deduped = existing.filter((u) => u.userId !== user.userId);
|
|
801
|
-
return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };
|
|
802
|
-
}),
|
|
803
|
-
removeTypingUser: (conversationId, userId) => set((state) => ({
|
|
804
|
-
typingUsers: {
|
|
805
|
-
...state.typingUsers,
|
|
806
|
-
[conversationId]: (state.typingUsers[conversationId] ?? []).filter(
|
|
807
|
-
(u) => u.userId !== userId
|
|
808
|
-
)
|
|
809
|
-
}
|
|
810
|
-
})),
|
|
811
|
-
setUserOnline: (userId) => set((state) => ({
|
|
812
|
-
onlineUsers: state.onlineUsers.includes(userId) ? state.onlineUsers : [...state.onlineUsers, userId]
|
|
813
|
-
})),
|
|
814
|
-
setUserOffline: (userId) => set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),
|
|
815
|
-
setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),
|
|
816
|
-
setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
|
|
817
|
-
setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
|
|
818
|
-
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
|
|
819
|
-
setSidebarOpen: (open) => set({ isSidebarOpen: open }),
|
|
820
|
-
toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),
|
|
821
|
-
setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),
|
|
822
|
-
toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),
|
|
823
|
-
setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open })
|
|
824
|
-
}));
|
|
957
|
+
// src/index.ts
|
|
958
|
+
init_chat_store();
|
|
825
959
|
|
|
826
960
|
// src/client-facade.ts
|
|
827
961
|
var AntzChatClient = class {
|
|
@@ -830,6 +964,7 @@ var AntzChatClient = class {
|
|
|
830
964
|
this.messages = messagesApi;
|
|
831
965
|
this.conversations = conversationsApi;
|
|
832
966
|
this.storage = storageApi;
|
|
967
|
+
this.users = usersApi;
|
|
833
968
|
this.socket = {
|
|
834
969
|
emit: socketEmit,
|
|
835
970
|
on: (event, handler) => getSocket().on(event, handler),
|
|
@@ -885,6 +1020,7 @@ var AntzChatClient = class {
|
|
|
885
1020
|
storageApi,
|
|
886
1021
|
tryGetSocket,
|
|
887
1022
|
uploadBatch,
|
|
888
|
-
useChatStore
|
|
1023
|
+
useChatStore,
|
|
1024
|
+
usersApi
|
|
889
1025
|
});
|
|
890
1026
|
//# sourceMappingURL=index.cjs.map
|