@antzsoft/chat-core 1.2.0 → 1.2.1

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 CHANGED
@@ -2451,6 +2451,9 @@ document.querySelectorAll('[data-conv-id]').forEach((el) => {
2451
2451
 
2452
2452
  ## Changelog
2453
2453
 
2454
+ ### v1.2.0
2455
+ - **Fix: `getSocket()` and `tryGetSocket()` now return the transit-aware proxy** — Previously these functions returned the raw Socket.IO socket, bypassing the `secureOn` decryption wrapper. Any integrator calling `getSocket().on('new_message', ...)` or `tryGetSocket().on(...)` directly would receive raw encrypted envelopes (`{v:1, iv:..., ct:...}`) instead of decrypted payloads. Both functions now return the same secure proxy that `connectSocket()` returns — all `.on()` calls automatically decrypt via transit when enabled. **No integration changes required — existing code that uses `getSocket()` or `tryGetSocket()` will now transparently receive decrypted data.**
2456
+
2454
2457
  ### v1.1.9
2455
2458
  - **Fix: Transit 403 on `GET /users/me` and `POST /users/me/devices` in external / authToken mode** — In external and authToken auth modes, `AntzChatProvider` calls `GET /users/me` immediately on mount to refresh the user profile, and push token registration (`POST /users/me/devices`) fires on auth state change — both before the socket connects and the ECDH transit session is established. With transit enforcement enabled these requests were receiving `403 Transit encryption required`. Both endpoints are now marked `@PreTransit()` on the server so they are reachable during the bootstrap window. **No integration changes required.**
2456
2459
  - **Fix: React Native / Hermes support for transit encryption** — The core SDK (`@antzsoft/chat-core`) now works on React Native and Hermes out of the box. When `globalThis.crypto.subtle` is unavailable (Hermes does not expose it), the SDK automatically falls back to `@noble/curves` (X25519 ECDH) and `@noble/ciphers` (AES-256-GCM) for both the handshake and all payload encryption/decryption. Previously the SDK crashed with `TypeError: Cannot read property 'subtle' of undefined` on RN. **No integration changes required — no extra packages to install.**
@@ -0,0 +1,7 @@
1
+ import {
2
+ useChatStore
3
+ } from "./chunk-GUO5QQGK.js";
4
+ export {
5
+ useChatStore
6
+ };
7
+ //# sourceMappingURL=chat.store-JC6QYDDL.js.map
@@ -35,9 +35,13 @@ var useChatStore = create((set) => ({
35
35
  setLastRead: (conversationId, messageId, readAt) => set((state) => ({
36
36
  lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } }
37
37
  })),
38
- setLastSeen: (userId, lastSeenAt) => set((state) => ({
39
- lastSeen: { ...state.lastSeen, [userId]: lastSeenAt }
40
- })),
38
+ setLastSeen: (userId, lastSeenAt) => set((state) => {
39
+ if (lastSeenAt === null) {
40
+ const { [userId]: _, ...rest } = state.lastSeen;
41
+ return { lastSeen: rest };
42
+ }
43
+ return { lastSeen: { ...state.lastSeen, [userId]: lastSeenAt } };
44
+ }),
41
45
  setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
42
46
  setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
43
47
  toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
@@ -51,4 +55,4 @@ var useChatStore = create((set) => ({
51
55
  export {
52
56
  useChatStore
53
57
  };
54
- //# sourceMappingURL=chunk-TB52RCSF.js.map
58
+ //# sourceMappingURL=chunk-GUO5QQGK.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 | null) => 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 if (lastSeenAt === null) {\n const { [userId]: _, ...rest } = state.lastSeen;\n return { lastSeen: rest };\n }\n return { 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":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -75,9 +75,13 @@ var init_chat_store = __esm({
75
75
  setLastRead: (conversationId, messageId, readAt) => set((state) => ({
76
76
  lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } }
77
77
  })),
78
- setLastSeen: (userId, lastSeenAt) => set((state) => ({
79
- lastSeen: { ...state.lastSeen, [userId]: lastSeenAt }
80
- })),
78
+ setLastSeen: (userId, lastSeenAt) => set((state) => {
79
+ if (lastSeenAt === null) {
80
+ const { [userId]: _, ...rest } = state.lastSeen;
81
+ return { lastSeen: rest };
82
+ }
83
+ return { lastSeen: { ...state.lastSeen, [userId]: lastSeenAt } };
84
+ }),
81
85
  setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
82
86
  setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
83
87
  toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
@@ -1287,7 +1291,10 @@ async function _doConnect(config, getToken) {
1287
1291
  });
1288
1292
  secureOn(_socket, "user_online", (event) => {
1289
1293
  Promise.resolve().then(() => (init_chat_store(), chat_store_exports)).then(({ useChatStore: useChatStore2 }) => {
1290
- useChatStore2.getState().setUserOnline(event.userId);
1294
+ const store = useChatStore2.getState();
1295
+ const e = event;
1296
+ store.setUserOnline(e.userId);
1297
+ store.setLastSeen(e.userId, null);
1291
1298
  });
1292
1299
  });
1293
1300
  secureOn(_socket, "user_offline", (event) => {