@antzsoft/chat-core 1.4.1 → 1.4.3
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 +58 -0
- package/dist/chat.store-UVTDBPEC.js +7 -0
- package/dist/{chunk-EOL5B7GS.js → chunk-UIYJAOGL.js} +4 -2
- package/dist/chunk-UIYJAOGL.js.map +1 -0
- package/dist/index.cjs +27 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +26 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/{storage-Pz2Taipp.d.cts → storage-D7GPq-Mm.d.cts} +22 -1
- package/dist/{storage-Pz2Taipp.d.ts → storage-D7GPq-Mm.d.ts} +22 -1
- package/package.json +1 -1
- package/dist/chat.store-DLNRJ5ZT.js +0 -7
- package/dist/chunk-EOL5B7GS.js.map +0 -1
- /package/dist/{chat.store-DLNRJ5ZT.js.map → chat.store-UVTDBPEC.js.map} +0 -0
package/README.md
CHANGED
|
@@ -764,6 +764,7 @@ import { messagesApi } from '@antzsoft/chat-core';
|
|
|
764
764
|
| `pin` | `(messageId: string) => Promise<Message>` | Pin a message. |
|
|
765
765
|
| `unpin` | `(messageId: string) => Promise<Message>` | Unpin a message. |
|
|
766
766
|
| `getPinned` | `(conversationId: string) => Promise<Message[]>` | List pinned messages in a conversation. |
|
|
767
|
+
| `forward` | `(messageId: string, targetConversationIds: string[]) => Promise<ForwardResult[]>` | Forward a message into one or more conversations (v1.4.2+). Max `MAX_FORWARD_TARGETS` (5) targets per call, reduced to 1 if the source message has `forwardDepth >= 5`. Each target is independent — check `success`/`error` per entry in the returned array. No hard cap on forward count. |
|
|
767
768
|
|
|
768
769
|
> **Delete permissions** — `delete()` (for everyone) requires either: the message belongs to the current user AND was sent within the delete window, OR the current user is a group admin. The server default window is **216,000 s (60 hours)** when `conversation.settings.messageConfig.deleteWindowSeconds` is not set. DMs have no admin role — only the sender can delete for everyone in a DM. `deleteForMe()` is always allowed for any message. See the [integration guide — Edit & Delete section](docs/integration-guide.html#step-edit) for a ready-to-use `getDeleteOptions()` helper.
|
|
769
770
|
|
|
@@ -812,6 +813,63 @@ await messagesApi.send('conv-abc', {
|
|
|
812
813
|
const results = await messagesApi.search({ query: 'deployment', conversationId: 'conv-abc' });
|
|
813
814
|
```
|
|
814
815
|
|
|
816
|
+
#### Forward Message (v1.4.2+)
|
|
817
|
+
|
|
818
|
+
Forwarding creates an **independent copy** of a message in each target conversation — never a shared row. Each copy gets its own ID, sequence number, read receipts, and delete lifecycle; deleting one copy never affects another, and none of them affect the original.
|
|
819
|
+
|
|
820
|
+
| Field / method | Type | Description |
|
|
821
|
+
|---|---|---|
|
|
822
|
+
| `messagesApi.forward(messageId, targetConversationIds, attachmentIds?)` | `Promise<ForwardResult[]>` | Forwards into up to `MAX_FORWARD_TARGETS` (5) conversations in one call — fewer if the source message is highly forwarded, see Limits below. Pass `attachmentIds` to forward only a subset of the source message's attachments (e.g. one image out of a multi-image message); omit it to forward the whole message unchanged. An ID not on the source message is ignored. |
|
|
823
|
+
| `Message.forwardedFrom` | `MessageForwardReference \| undefined` | Present on a message created via forwarding. |
|
|
824
|
+
| `MAX_FORWARD_TARGETS` | `number` | `5` — matches the server's normal-case cap. |
|
|
825
|
+
| `HIGHLY_FORWARDED_DEPTH_THRESHOLD` | `number` | `5` — matches the server's `forwardDepth` value that triggers BOTH the "Forwarded many times" label and the reduced fan-out cap. Use this for the label instead of hardcoding a number. |
|
|
826
|
+
|
|
827
|
+
**Limits:**
|
|
828
|
+
|
|
829
|
+
| Limit | Value | Behavior when exceeded |
|
|
830
|
+
|---|---|---|
|
|
831
|
+
| Targets per call (normal) | 5 (`MAX_FORWARD_TARGETS`) | Client: `ForwardPicker` disables further selection. Server: request rejected with a validation error if bypassed. |
|
|
832
|
+
| Targets per call — highly-forwarded content (`forwardDepth >= 5`) | **1** | Server silently truncates to the first target and reports every dropped target back as an explicit `{ success: false, error }` entry in `ForwardResult[]` — never a validation error, never a fully blocked forward. Matches WhatsApp's actual behavior: reduced fan-out, not a forwarding ban. |
|
|
833
|
+
| Forward API rate limit | 20 calls/min per user | `429` if exceeded (server-side `@Throttle`, not currently surfaced as a distinct client-side pre-check). |
|
|
834
|
+
| Forward-count hard cap | **None** | A message can be forwarded any number of times — there is no "forwarded too many times, blocked" state. Only fan-out width is reduced at high `forwardDepth`; `forwardDepth` itself only ever drives the "Forwarded many times" label. |
|
|
835
|
+
|
|
836
|
+
Because dropped targets from the highly-forwarded cap come back as regular `ForwardResult` failures, existing "Forwarded to N/M chats" UI (see the example below) needs no special-casing to handle it correctly.
|
|
837
|
+
|
|
838
|
+
```typescript
|
|
839
|
+
interface MessageForwardReference {
|
|
840
|
+
originalMessageId: string; // one hop back only — never the root of a longer chain
|
|
841
|
+
originalConversationId: string; // one hop back only
|
|
842
|
+
originalSenderId: string; // one hop back only — NOT the original author past 1 hop
|
|
843
|
+
forwardDepth: number; // accumulates across the whole chain
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
interface ForwardResult {
|
|
847
|
+
conversationId: string;
|
|
848
|
+
success: boolean;
|
|
849
|
+
message?: Message; // present when success is true
|
|
850
|
+
error?: string; // present when success is false
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
```typescript
|
|
855
|
+
const results = await messagesApi.forward(messageId, [convA, convB, convC]);
|
|
856
|
+
const failed = results.filter(r => !r.success);
|
|
857
|
+
if (failed.length > 0) {
|
|
858
|
+
console.warn(`Forward failed for ${failed.length}/${results.length} conversations`, failed);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Forward only one attachment out of a multi-attachment message (e.g. image 2 of 3)
|
|
862
|
+
await messagesApi.forward(messageId, [convA], [message.content.attachments![1].id]);
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
**Where `forwardedFrom` is populated.** Every place a `Message` object is returned — `messagesApi.list`/`get`, the `new_message` socket event, `syncApi` (reconnect/resync), and REST list/search/starred/pinned — always includes `forwardedFrom` when present. **`conversation_updated`'s `lastMessage` field also includes it** (a conversation-list preview showing a forwarded message can render the "Forwarded" label without a separate message fetch). If `forwardDepth` ever reads as absent/`0` where you expected a value, that's a bug to report, not expected behavior — it should never be silently missing on any of these paths.
|
|
866
|
+
|
|
867
|
+
**Why only one hop of lineage is kept.** `forwardedFrom` always points at the *immediate* message being forwarded, never the ultimate original — matching WhatsApp: if you forward a message that was itself already forwarded, the new copy's `originalMessageId`/`originalSenderId` reference that intermediate copy, not the very first message in the chain. This is intentional: it keeps the true original author untraceable after more than one hop (privacy), while `forwardDepth` still accumulates across the whole chain. `forwardDepth` drives two things, both purely about slowing spread, never about blocking it: the "Forwarded many times" badge, and server-side, the reduced 1-target fan-out cap — both gated on the SAME threshold, `HIGHLY_FORWARDED_DEPTH_THRESHOLD` (currently `5`, exported from the package root). Use that constant for the label rather than hardcoding a number, so the two never drift apart again. There is no API to walk a message's full forward history — only the immediate parent is ever resolvable, and there is no forward-count ceiling that ever blocks forwarding outright.
|
|
868
|
+
|
|
869
|
+
**Attachments are never re-uploaded.** A forwarded attachment reuses the same underlying storage object as the source message — only the message row referencing it is new. This is transparent to SDK consumers; `forward()` handles it server-side.
|
|
870
|
+
|
|
871
|
+
**Rendering:** show a "Forwarded" (or "Forwarded many times" at `forwardDepth >= HIGHLY_FORWARDED_DEPTH_THRESHOLD`) label when `message.forwardedFrom` is present — do not render a sender name or content preview for it (unlike `replyTo`), since the message's own `content` already holds what was forwarded. The built-in `MessageItem` component in both `@antzsoft/chat-web-sdk` and `@antzsoft/chat-rn-sdk` already renders this label using the exported constant and exposes a "Forward" action in the message menu — no extra wiring needed if you're using the prebuilt UI.
|
|
872
|
+
|
|
815
873
|
#### Jump to first unread message
|
|
816
874
|
|
|
817
875
|
Use `direction: 'after'` with the user's `lastReadMessageId` as the cursor to fetch only the unread messages. This powers a scroll-to-first-unread experience with an "↑ Unread messages" divider.
|
|
@@ -9,11 +9,12 @@ var useChatStore = create((set) => ({
|
|
|
9
9
|
lastSeen: {},
|
|
10
10
|
replyingTo: null,
|
|
11
11
|
editingMessage: null,
|
|
12
|
+
forwardingMessage: null,
|
|
12
13
|
isSidebarOpen: true,
|
|
13
14
|
isGroupInfoOpen: false,
|
|
14
15
|
isStarredPanelOpen: false,
|
|
15
16
|
messageInfoId: null,
|
|
16
|
-
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null }),
|
|
17
|
+
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null, forwardingMessage: null }),
|
|
17
18
|
setPendingTarget: (target) => set({ pendingTarget: target }),
|
|
18
19
|
addTypingUser: (conversationId, user) => set((state) => {
|
|
19
20
|
const existing = state.typingUsers[conversationId] ?? [];
|
|
@@ -45,6 +46,7 @@ var useChatStore = create((set) => ({
|
|
|
45
46
|
}),
|
|
46
47
|
setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
|
|
47
48
|
setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
|
|
49
|
+
setForwardingMessage: (message) => set({ forwardingMessage: message }),
|
|
48
50
|
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
|
|
49
51
|
setSidebarOpen: (open) => set({ isSidebarOpen: open }),
|
|
50
52
|
toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),
|
|
@@ -57,4 +59,4 @@ var useChatStore = create((set) => ({
|
|
|
57
59
|
export {
|
|
58
60
|
useChatStore
|
|
59
61
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
62
|
+
//# sourceMappingURL=chunk-UIYJAOGL.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 /** Message staged in the forward picker, null = picker closed. Unlike replyingTo,\n * this does not fold into the next composer send — forwarding targets a different\n * conversation and needs its own conversation-picker UI. */\n forwardingMessage: Message | null;\n isSidebarOpen: boolean;\n isGroupInfoOpen: boolean;\n isStarredPanelOpen: boolean;\n /** messageId currently shown in the Message Info panel, null = closed */\n messageInfoId: string | null;\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 setForwardingMessage: (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 setMessageInfoId: (id: string | null) => 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 forwardingMessage: null,\n isSidebarOpen: true,\n isGroupInfoOpen: false,\n isStarredPanelOpen: false,\n messageInfoId: null,\n\n setActiveConversation: (id) =>\n set({ activeConversationId: id, replyingTo: null, editingMessage: null, forwardingMessage: 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 setForwardingMessage: (message) => set({ forwardingMessage: message }),\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 setMessageInfoId: (id: string | null) => set({ messageInfoId: id }),\n}));\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -49,11 +49,12 @@ var init_chat_store = __esm({
|
|
|
49
49
|
lastSeen: {},
|
|
50
50
|
replyingTo: null,
|
|
51
51
|
editingMessage: null,
|
|
52
|
+
forwardingMessage: null,
|
|
52
53
|
isSidebarOpen: true,
|
|
53
54
|
isGroupInfoOpen: false,
|
|
54
55
|
isStarredPanelOpen: false,
|
|
55
56
|
messageInfoId: null,
|
|
56
|
-
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null }),
|
|
57
|
+
setActiveConversation: (id) => set({ activeConversationId: id, replyingTo: null, editingMessage: null, forwardingMessage: null }),
|
|
57
58
|
setPendingTarget: (target) => set({ pendingTarget: target }),
|
|
58
59
|
addTypingUser: (conversationId, user) => set((state) => {
|
|
59
60
|
const existing = state.typingUsers[conversationId] ?? [];
|
|
@@ -85,6 +86,7 @@ var init_chat_store = __esm({
|
|
|
85
86
|
}),
|
|
86
87
|
setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),
|
|
87
88
|
setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),
|
|
89
|
+
setForwardingMessage: (message) => set({ forwardingMessage: message }),
|
|
88
90
|
toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
|
|
89
91
|
setSidebarOpen: (open) => set({ isSidebarOpen: open }),
|
|
90
92
|
toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),
|
|
@@ -106,6 +108,8 @@ __export(src_exports, {
|
|
|
106
108
|
AntzChatPermissionError: () => AntzChatPermissionError,
|
|
107
109
|
AntzChatServerError: () => AntzChatServerError,
|
|
108
110
|
AntzChatValidationError: () => AntzChatValidationError,
|
|
111
|
+
HIGHLY_FORWARDED_DEPTH_THRESHOLD: () => HIGHLY_FORWARDED_DEPTH_THRESHOLD,
|
|
112
|
+
MAX_FORWARD_TARGETS: () => MAX_FORWARD_TARGETS,
|
|
109
113
|
MENTION_ALL_ID: () => MENTION_ALL_ID,
|
|
110
114
|
appConfigApi: () => appConfigApi,
|
|
111
115
|
authApi: () => authApi,
|
|
@@ -1010,6 +1014,8 @@ function resolveSystemMessageText(message, currentUserId) {
|
|
|
1010
1014
|
}
|
|
1011
1015
|
|
|
1012
1016
|
// src/api/messages.ts
|
|
1017
|
+
var MAX_FORWARD_TARGETS = 5;
|
|
1018
|
+
var HIGHLY_FORWARDED_DEPTH_THRESHOLD = 5;
|
|
1013
1019
|
var messagesApi = {
|
|
1014
1020
|
async list(conversationId, params = {}) {
|
|
1015
1021
|
const { cursor, direction, ...rest } = params;
|
|
@@ -1103,6 +1109,24 @@ var messagesApi = {
|
|
|
1103
1109
|
async getReceipts(messageId) {
|
|
1104
1110
|
const { data } = await getApiClient().get(`/messages/${messageId}/receipts`);
|
|
1105
1111
|
return data;
|
|
1112
|
+
},
|
|
1113
|
+
/**
|
|
1114
|
+
* Forwards a message into one or more target conversations (max MAX_FORWARD_TARGETS
|
|
1115
|
+
* per call, also enforced server-side). Each target is independent — one failing
|
|
1116
|
+
* (e.g. no longer a participant) does not block the others; check `success`/`error`
|
|
1117
|
+
* per entry in the returned array.
|
|
1118
|
+
*
|
|
1119
|
+
* Pass `attachmentIds` to forward only a subset of the source message's attachments
|
|
1120
|
+
* (e.g. one image out of a multi-image message) — omit it to forward the whole
|
|
1121
|
+
* message, including all its attachments, unchanged. An ID not present on the
|
|
1122
|
+
* source message is ignored server-side.
|
|
1123
|
+
*/
|
|
1124
|
+
async forward(messageId, targetConversationIds, attachmentIds) {
|
|
1125
|
+
const { data } = await getApiClient().post(
|
|
1126
|
+
`/messages/${messageId}/forward`,
|
|
1127
|
+
{ targetConversationIds, ...attachmentIds ? { attachmentIds } : {} }
|
|
1128
|
+
);
|
|
1129
|
+
return data;
|
|
1106
1130
|
}
|
|
1107
1131
|
};
|
|
1108
1132
|
|
|
@@ -2096,6 +2120,8 @@ var AntzChatClient = class {
|
|
|
2096
2120
|
AntzChatPermissionError,
|
|
2097
2121
|
AntzChatServerError,
|
|
2098
2122
|
AntzChatValidationError,
|
|
2123
|
+
HIGHLY_FORWARDED_DEPTH_THRESHOLD,
|
|
2124
|
+
MAX_FORWARD_TARGETS,
|
|
2099
2125
|
MENTION_ALL_ID,
|
|
2100
2126
|
appConfigApi,
|
|
2101
2127
|
authApi,
|