@enfin/chat 1.2.0
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 +224 -0
- package/dist/assets/music/i_phone_message.mp3 +0 -0
- package/dist/call/WebRTCManager.d.ts +54 -0
- package/dist/call/WebRTCManager.js +274 -0
- package/dist/call/signaling.d.ts +3 -0
- package/dist/call/signaling.js +24 -0
- package/dist/call/types.d.ts +25 -0
- package/dist/call/types.js +13 -0
- package/dist/components/Chat.d.ts +14 -0
- package/dist/components/Chat.js +452 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +2 -0
- package/dist/context/ChatContext.d.ts +59 -0
- package/dist/context/ChatContext.js +647 -0
- package/dist/esm/call/WebRTCManager.d.ts +54 -0
- package/dist/esm/call/WebRTCManager.js +274 -0
- package/dist/esm/call/signaling.d.ts +3 -0
- package/dist/esm/call/signaling.js +24 -0
- package/dist/esm/call/types.d.ts +25 -0
- package/dist/esm/call/types.js +13 -0
- package/dist/esm/components/Chat.d.ts +14 -0
- package/dist/esm/components/Chat.js +452 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +2 -0
- package/dist/esm/context/ChatContext.d.ts +59 -0
- package/dist/esm/context/ChatContext.js +647 -0
- package/dist/esm/hooks/index.d.ts +6 -0
- package/dist/esm/hooks/index.js +6 -0
- package/dist/esm/hooks/useCall.d.ts +15 -0
- package/dist/esm/hooks/useCall.js +38 -0
- package/dist/esm/hooks/useChat.d.ts +23 -0
- package/dist/esm/hooks/useChat.js +40 -0
- package/dist/esm/hooks/useMessages.d.ts +17 -0
- package/dist/esm/hooks/useMessages.js +38 -0
- package/dist/esm/hooks/usePresence.d.ts +4 -0
- package/dist/esm/hooks/usePresence.js +12 -0
- package/dist/esm/hooks/useRooms.d.ts +9 -0
- package/dist/esm/hooks/useRooms.js +19 -0
- package/dist/esm/hooks/useSocket.d.ts +7 -0
- package/dist/esm/hooks/useSocket.js +92 -0
- package/dist/esm/index.d.ts +11 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/utils/index.d.ts +2 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/ringtone.d.ts +2 -0
- package/dist/esm/utils/ringtone.js +39 -0
- package/dist/esm/utils/testUtils.d.ts +102 -0
- package/dist/esm/utils/testUtils.js +153 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/useCall.d.ts +15 -0
- package/dist/hooks/useCall.js +38 -0
- package/dist/hooks/useChat.d.ts +23 -0
- package/dist/hooks/useChat.js +40 -0
- package/dist/hooks/useMessages.d.ts +17 -0
- package/dist/hooks/useMessages.js +38 -0
- package/dist/hooks/usePresence.d.ts +4 -0
- package/dist/hooks/usePresence.js +12 -0
- package/dist/hooks/useRooms.d.ts +9 -0
- package/dist/hooks/useRooms.js +19 -0
- package/dist/hooks/useSocket.d.ts +7 -0
- package/dist/hooks/useSocket.js +92 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +15 -0
- package/dist/public/music/i_phone_message.mp3 +0 -0
- package/dist/style.css +1226 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/ringtone.d.ts +2 -0
- package/dist/utils/ringtone.js +39 -0
- package/dist/utils/testUtils.d.ts +102 -0
- package/dist/utils/testUtils.js +153 -0
- package/package.json +44 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2
|
+
import defaultRingtoneUrl from '../assets/music/i_phone_message.mp3';
|
|
3
|
+
let audioEl = null;
|
|
4
|
+
let currentUrl = null;
|
|
5
|
+
function getAudio(url) {
|
|
6
|
+
const target = url || defaultRingtoneUrl;
|
|
7
|
+
if (!audioEl || currentUrl !== target) {
|
|
8
|
+
if (audioEl) {
|
|
9
|
+
audioEl.pause();
|
|
10
|
+
audioEl.src = '';
|
|
11
|
+
}
|
|
12
|
+
audioEl = new Audio(target);
|
|
13
|
+
audioEl.loop = true;
|
|
14
|
+
audioEl.preload = 'auto';
|
|
15
|
+
currentUrl = target;
|
|
16
|
+
}
|
|
17
|
+
return audioEl;
|
|
18
|
+
}
|
|
19
|
+
export function startRingtone(url) {
|
|
20
|
+
try {
|
|
21
|
+
const audio = getAudio(url);
|
|
22
|
+
audio.currentTime = 0;
|
|
23
|
+
const playPromise = audio.play();
|
|
24
|
+
if (playPromise && typeof playPromise.catch === 'function') {
|
|
25
|
+
playPromise.catch((err) => {
|
|
26
|
+
console.log('[RINGTONE] play() rejected:', err?.message || err);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
console.log('[RINGTONE] start failed:', err?.message || err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function stopRingtone() {
|
|
35
|
+
if (!audioEl)
|
|
36
|
+
return;
|
|
37
|
+
audioEl.pause();
|
|
38
|
+
audioEl.currentTime = 0;
|
|
39
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Socket } from 'socket.io-client';
|
|
2
|
+
/**
|
|
3
|
+
* Test utilities for developers to create test users and simulate interactions
|
|
4
|
+
*
|
|
5
|
+
* This utility allows developers to:
|
|
6
|
+
* 1. Create multiple test users that can chat with each other
|
|
7
|
+
* 2. Send messages between test users
|
|
8
|
+
* 3. Make audio calls between test users
|
|
9
|
+
* 4. Test custom socket events
|
|
10
|
+
*/
|
|
11
|
+
export interface TestUser {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
socket: Socket;
|
|
15
|
+
rooms: string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a test user with automatic socket connection
|
|
19
|
+
*
|
|
20
|
+
* @param serverUrl - Chat server URL
|
|
21
|
+
* @param userId - User ID (optional, generated if not provided)
|
|
22
|
+
* @param userName - User name
|
|
23
|
+
* @returns Test user object with socket connection
|
|
24
|
+
*/
|
|
25
|
+
export declare function createTestUser(serverUrl: string, userName: string, userId?: string): TestUser;
|
|
26
|
+
/**
|
|
27
|
+
* Create multiple test users for testing
|
|
28
|
+
*
|
|
29
|
+
* @param serverUrl - Chat server URL
|
|
30
|
+
* @param userNames - Array of user names
|
|
31
|
+
* @returns Array of test users
|
|
32
|
+
*/
|
|
33
|
+
export declare function createTestUsers(serverUrl: string, userNames: string[]): TestUser[];
|
|
34
|
+
/**
|
|
35
|
+
* Create a test room between users
|
|
36
|
+
*
|
|
37
|
+
* @param users - Users to add to the room
|
|
38
|
+
* @param roomName - Room name
|
|
39
|
+
* @param isDirect - Whether this is a direct chat
|
|
40
|
+
* @returns Promise resolving to the created room
|
|
41
|
+
*/
|
|
42
|
+
export declare function createTestRoom(users: TestUser[], roomName: string, isDirect?: boolean): Promise<any>;
|
|
43
|
+
/**
|
|
44
|
+
* Send a message from one user to another
|
|
45
|
+
*
|
|
46
|
+
* @param from - Sending user
|
|
47
|
+
* @param roomId - Room ID
|
|
48
|
+
* @param content - Message content
|
|
49
|
+
* @returns Promise resolving when message is sent
|
|
50
|
+
*/
|
|
51
|
+
export declare function sendMessage(from: TestUser, roomId: string, content: string): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Start an audio call
|
|
54
|
+
*
|
|
55
|
+
* @param from - Initiating user
|
|
56
|
+
* @param to - Target user
|
|
57
|
+
* @param roomId - Room ID
|
|
58
|
+
* @returns Promise resolving when call is initiated
|
|
59
|
+
*/
|
|
60
|
+
export declare function startCall(from: TestUser, to: TestUser, roomId: string): Promise<any>;
|
|
61
|
+
/**
|
|
62
|
+
* Accept an incoming call
|
|
63
|
+
*
|
|
64
|
+
* @param to - User accepting call
|
|
65
|
+
* @param callId - Call ID
|
|
66
|
+
* @returns Promise resolving when call is accepted
|
|
67
|
+
*/
|
|
68
|
+
export declare function acceptCall(to: TestUser, callId: string): Promise<any>;
|
|
69
|
+
/**
|
|
70
|
+
* End a call
|
|
71
|
+
*
|
|
72
|
+
* @param by - User ending call
|
|
73
|
+
* @param callId - Call ID
|
|
74
|
+
* @returns Promise resolving when call is ended
|
|
75
|
+
*/
|
|
76
|
+
export declare function endCall(by: TestUser, callId: string): Promise<any>;
|
|
77
|
+
/**
|
|
78
|
+
* Listen for socket events (useful for testing)
|
|
79
|
+
*
|
|
80
|
+
* @param socket - Socket to listen on
|
|
81
|
+
* @param event - Event name
|
|
82
|
+
* @param callback - Callback function
|
|
83
|
+
* @returns Cleanup function to remove listener
|
|
84
|
+
*/
|
|
85
|
+
export declare function onSocketEvent(socket: Socket, event: string, callback: (data: any) => void): () => void;
|
|
86
|
+
/**
|
|
87
|
+
* Listen to custom socket events (exposed by ChatProvider)
|
|
88
|
+
*
|
|
89
|
+
* @param eventName - Event name to listen to
|
|
90
|
+
* @param callback - Callback function
|
|
91
|
+
* @returns Cleanup function
|
|
92
|
+
*/
|
|
93
|
+
export declare function onCustomSocketEvent(eventName: string, callback: (data: any) => void): () => void;
|
|
94
|
+
/**
|
|
95
|
+
* Emit custom event through the socket
|
|
96
|
+
*
|
|
97
|
+
* @param user - User to emit from
|
|
98
|
+
* @param event - Event name
|
|
99
|
+
* @param data - Event data
|
|
100
|
+
* @returns Promise resolving when event is sent
|
|
101
|
+
*/
|
|
102
|
+
export declare function emitCustomEvent(user: TestUser, event: string, data?: any): Promise<any>;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import io from 'socket.io-client';
|
|
2
|
+
/**
|
|
3
|
+
* Create a test user with automatic socket connection
|
|
4
|
+
*
|
|
5
|
+
* @param serverUrl - Chat server URL
|
|
6
|
+
* @param userId - User ID (optional, generated if not provided)
|
|
7
|
+
* @param userName - User name
|
|
8
|
+
* @returns Test user object with socket connection
|
|
9
|
+
*/
|
|
10
|
+
export function createTestUser(serverUrl, userName, userId) {
|
|
11
|
+
const id = userId || `user_${Math.random().toString(36).substr(2, 9)}`;
|
|
12
|
+
const socket = io(`${serverUrl}/chat`, {
|
|
13
|
+
auth: { userId: id, userName, tenantId: id },
|
|
14
|
+
transports: ['websocket'],
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
id,
|
|
18
|
+
name: userName,
|
|
19
|
+
socket,
|
|
20
|
+
rooms: [],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create multiple test users for testing
|
|
25
|
+
*
|
|
26
|
+
* @param serverUrl - Chat server URL
|
|
27
|
+
* @param userNames - Array of user names
|
|
28
|
+
* @returns Array of test users
|
|
29
|
+
*/
|
|
30
|
+
export function createTestUsers(serverUrl, userNames) {
|
|
31
|
+
return userNames.map((name, index) => {
|
|
32
|
+
const userId = `test_user_${String(index + 1).padStart(2, '0')}`;
|
|
33
|
+
return createTestUser(serverUrl, name, userId);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a test room between users
|
|
38
|
+
*
|
|
39
|
+
* @param users - Users to add to the room
|
|
40
|
+
* @param roomName - Room name
|
|
41
|
+
* @param isDirect - Whether this is a direct chat
|
|
42
|
+
* @returns Promise resolving to the created room
|
|
43
|
+
*/
|
|
44
|
+
export async function createTestRoom(users, roomName, isDirect = false) {
|
|
45
|
+
const roomId = `room_${Date.now()}`;
|
|
46
|
+
if (isDirect && users.length !== 2) {
|
|
47
|
+
throw new Error('Direct rooms require exactly 2 users');
|
|
48
|
+
}
|
|
49
|
+
// Create room (first user creates it)
|
|
50
|
+
await users[0].socket.emitWithAck('room:create', {
|
|
51
|
+
name: roomName,
|
|
52
|
+
type: isDirect ? 'direct' : 'group',
|
|
53
|
+
members: users.map(u => u.id),
|
|
54
|
+
});
|
|
55
|
+
// Wait a bit for room to propagate
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
57
|
+
// Join all users to the room
|
|
58
|
+
for (const user of users) {
|
|
59
|
+
await user.socket.emitWithAck('join', { roomId: roomId });
|
|
60
|
+
user.rooms.push(roomId);
|
|
61
|
+
}
|
|
62
|
+
return { id: roomId, name: roomName, type: isDirect ? 'direct' : 'group' };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Send a message from one user to another
|
|
66
|
+
*
|
|
67
|
+
* @param from - Sending user
|
|
68
|
+
* @param roomId - Room ID
|
|
69
|
+
* @param content - Message content
|
|
70
|
+
* @returns Promise resolving when message is sent
|
|
71
|
+
*/
|
|
72
|
+
export async function sendMessage(from, roomId, content) {
|
|
73
|
+
return from.socket.emitWithAck('message:send', {
|
|
74
|
+
roomId,
|
|
75
|
+
content,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Start an audio call
|
|
80
|
+
*
|
|
81
|
+
* @param from - Initiating user
|
|
82
|
+
* @param to - Target user
|
|
83
|
+
* @param roomId - Room ID
|
|
84
|
+
* @returns Promise resolving when call is initiated
|
|
85
|
+
*/
|
|
86
|
+
export async function startCall(from, to, roomId) {
|
|
87
|
+
return from.socket.emitWithAck('call:initiate', {
|
|
88
|
+
roomId,
|
|
89
|
+
participantId: to.id,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Accept an incoming call
|
|
94
|
+
*
|
|
95
|
+
* @param to - User accepting call
|
|
96
|
+
* @param callId - Call ID
|
|
97
|
+
* @returns Promise resolving when call is accepted
|
|
98
|
+
*/
|
|
99
|
+
export async function acceptCall(to, callId) {
|
|
100
|
+
return to.socket.emitWithAck('call:accept', { callId });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* End a call
|
|
104
|
+
*
|
|
105
|
+
* @param by - User ending call
|
|
106
|
+
* @param callId - Call ID
|
|
107
|
+
* @returns Promise resolving when call is ended
|
|
108
|
+
*/
|
|
109
|
+
export async function endCall(by, callId) {
|
|
110
|
+
return by.socket.emitWithAck('call:end', { callId });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Listen for socket events (useful for testing)
|
|
114
|
+
*
|
|
115
|
+
* @param socket - Socket to listen on
|
|
116
|
+
* @param event - Event name
|
|
117
|
+
* @param callback - Callback function
|
|
118
|
+
* @returns Cleanup function to remove listener
|
|
119
|
+
*/
|
|
120
|
+
export function onSocketEvent(socket, event, callback) {
|
|
121
|
+
socket.on(event, callback);
|
|
122
|
+
return () => socket.off(event, callback);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Listen to custom socket events (exposed by ChatProvider)
|
|
126
|
+
*
|
|
127
|
+
* @param eventName - Event name to listen to
|
|
128
|
+
* @param callback - Callback function
|
|
129
|
+
* @returns Cleanup function
|
|
130
|
+
*/
|
|
131
|
+
export function onCustomSocketEvent(eventName, callback) {
|
|
132
|
+
const handler = (event) => {
|
|
133
|
+
if (event.detail.event === eventName) {
|
|
134
|
+
callback(event.detail.data);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
window.addEventListener('chat:socket-event', handler);
|
|
138
|
+
return () => window.removeEventListener('chat:socket-event', handler);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Emit custom event through the socket
|
|
142
|
+
*
|
|
143
|
+
* @param user - User to emit from
|
|
144
|
+
* @param event - Event name
|
|
145
|
+
* @param data - Event data
|
|
146
|
+
* @returns Promise resolving when event is sent
|
|
147
|
+
*/
|
|
148
|
+
export function emitCustomEvent(user, event, data) {
|
|
149
|
+
if (user.socket.connected) {
|
|
150
|
+
return user.socket.emitWithAck(event, data);
|
|
151
|
+
}
|
|
152
|
+
return Promise.reject('Socket not connected');
|
|
153
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@enfin/chat",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "React frontend SDK for chat platform",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./styles.css": "./dist/style.css"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.json --module esnext --outDir dist/esm && node -e \"const fs=require('fs');fs.copyFileSync('src/styles.css','dist/style.css');fs.cpSync('public','dist/public',{recursive:true});fs.cpSync('src/assets','dist/assets',{recursive:true});\"",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"test": "jest"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": "^18.0.0",
|
|
24
|
+
"react-dom": "^18.0.0",
|
|
25
|
+
"socket.io-client": "^4.6.0"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@enfin/chat-shared": "^1.0.0",
|
|
29
|
+
"socket.io-client": "^4.6.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/react": "^18.0.0",
|
|
33
|
+
"@types/react-dom": "^18.0.0",
|
|
34
|
+
"typescript": "^5.0.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"style": "src/styles.css"
|
|
44
|
+
}
|