Skip to content

Commit b61c78b

Browse files
committed
chore: use esbuild instead of webpack
1 parent b7335a6 commit b61c78b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+5721
-36460
lines changed

app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ app.use((req, res, next) => {
2020
app.use("/api", apiController);
2121

2222
if (process.env.NODE_ENV === "production") {
23-
app.use(express.static("client/build"));
23+
app.use(express.static("client/dist"));
2424
app.get("*", (req, res) => {
25-
res.sendFile(path.join(__dirname, "../client/build", "index.html"));
25+
res.sendFile(path.join(__dirname, "../client/dist", "index.html"));
2626
});
2727
} else {
2828
app.get("/*", (req, res) => {

backend/socket.io/index.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ export interface CustomSocket extends Socket {
99

1010
let io: Server = null;
1111
export enum SOCKET_TOPIC {
12-
CHAT_MESSAGE='chat-message',
13-
LIMIT_REACHED='limit-reached',
14-
ON_ALICE_JOIN='on-alice-join',
12+
CHAT_MESSAGE = 'chat-message',
13+
LIMIT_REACHED = 'limit-reached',
14+
ON_ALICE_JOIN = 'on-alice-join',
1515
DELIVERED = 'delivered',
1616
ON_ALICE_DISCONNECTED = 'on-alice-disconnect',
1717
MESSAGE = 'message',
@@ -35,7 +35,12 @@ export const initSocket = (server) => {
3535
return io;
3636
}
3737

38-
io = new Server(server, { allowEIO3: true });
38+
io = new Server(server, {
39+
allowEIO3: true, cors: {
40+
origin: "*",
41+
credentials: true
42+
}
43+
});
3944
// eslint-disable-next-line no-console
4045
console.log("Websocket is up!");
4146

@@ -47,7 +52,7 @@ export const initSocket = (server) => {
4752

4853
export const socketEmit = <T extends keyof emitDataTypes>(topic: T, sid: string, data: emitDataTypes[T]): void => {
4954
const socket = io.sockets.sockets.get(sid);
50-
if(!socket) {
55+
if (!socket) {
5156
console.warn("SKIPPING. No socket found.");
5257
return;
5358
}

client/.env.sample

Lines changed: 0 additions & 1 deletion
This file was deleted.

client/README.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

client/app.ts

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
import { createChatInstance, setConfig, utils } from '@chat-e2ee/service';
2+
3+
setConfig({
4+
apiURL: 'http://localhost:3001',
5+
socketURL: 'http://localhost:3001'
6+
});
7+
// State
8+
let chat: any = null;
9+
let userId: string = '';
10+
let channelHash: string = '';
11+
let privateKey: string = '';
12+
13+
// DOM Elements
14+
// DOM Elements
15+
const setupOverlay = document.getElementById('setup-overlay')!;
16+
const initialActions = document.getElementById('initial-actions')!;
17+
const createHashView = document.getElementById('create-hash-view')!;
18+
const joinHashView = document.getElementById('join-hash-view')!;
19+
const finalActions = document.getElementById('final-actions')!;
20+
21+
const showCreateBtn = document.getElementById('show-create-hash') as HTMLButtonElement;
22+
const showJoinBtn = document.getElementById('show-join-hash') as HTMLButtonElement;
23+
const backBtn = document.getElementById('back-btn') as HTMLButtonElement;
24+
const copyHashBtn = document.getElementById('copy-hash-btn') as HTMLButtonElement;
25+
26+
const generatedHashDisplay = document.getElementById('generated-hash-display') as HTMLInputElement;
27+
const hashInput = document.getElementById('channel-hash') as HTMLInputElement;
28+
const joinBtn = document.getElementById('join-btn') as HTMLButtonElement;
29+
const setupStatus = document.getElementById('setup-status')!;
30+
31+
const chatContainer = document.getElementById('chat-container')!;
32+
const messagesArea = document.getElementById('messages-area')!;
33+
const msgInput = document.getElementById('msg-input') as HTMLInputElement;
34+
const sendBtn = document.getElementById('send-btn') as HTMLButtonElement;
35+
const startCallBtn = document.getElementById('start-call-btn') as HTMLButtonElement;
36+
const chatHeader = document.querySelector('header')!;
37+
const participantInfo = document.getElementById('participant-info')!;
38+
const headerHashDisplay = document.getElementById('channel-hash-display')!;
39+
const headerHashText = document.getElementById('header-hash')!;
40+
const copyHeaderHashBtn = document.getElementById('copy-header-hash') as HTMLButtonElement;
41+
42+
// Call Elements
43+
const callOverlay = document.getElementById('call-overlay')!;
44+
const callStatusText = document.getElementById('call-status')!;
45+
const endCallBtn = document.getElementById('end-call-btn') as HTMLButtonElement;
46+
const callDuration = document.getElementById('call-duration')!;
47+
48+
// Initialize Chat
49+
async function initChat() {
50+
try {
51+
setupStatus.textContent = 'Initializing secure keys...';
52+
chat = createChatInstance();
53+
await chat.init();
54+
55+
const keys = chat.getKeyPair();
56+
privateKey = keys.privateKey;
57+
setupStatus.textContent = '';
58+
59+
// Check for URL hash on load
60+
handleUrlHash();
61+
} catch (err) {
62+
console.error('Init error:', err);
63+
setupStatus.textContent = 'Initialization failed. Refresh and try again.';
64+
}
65+
}
66+
67+
// UI Navigation
68+
function showView(view: 'initial' | 'create' | 'join') {
69+
initialActions.classList.add('hidden');
70+
createHashView.classList.add('hidden');
71+
joinHashView.classList.add('hidden');
72+
finalActions.classList.add('hidden');
73+
setupStatus.textContent = '';
74+
75+
if (view === 'initial') {
76+
initialActions.classList.remove('hidden');
77+
} else if (view === 'create') {
78+
createHashView.classList.remove('hidden');
79+
finalActions.classList.remove('hidden');
80+
} else if (view === 'join') {
81+
joinHashView.classList.remove('hidden');
82+
finalActions.classList.remove('hidden');
83+
hashInput.focus();
84+
}
85+
}
86+
87+
showCreateBtn.addEventListener('click', async () => {
88+
showView('create');
89+
try {
90+
generatedHashDisplay.value = 'Generating...';
91+
const linkObj = await chat.getLink();
92+
generatedHashDisplay.value = linkObj.hash;
93+
channelHash = linkObj.hash;
94+
} catch (err) {
95+
setupStatus.textContent = 'Failed to generate hash.';
96+
}
97+
});
98+
99+
showJoinBtn.addEventListener('click', () => {
100+
showView('join');
101+
});
102+
103+
backBtn.addEventListener('click', () => {
104+
showView('initial');
105+
channelHash = '';
106+
hashInput.value = '';
107+
});
108+
109+
copyHashBtn.addEventListener('click', () => {
110+
navigator.clipboard.writeText(generatedHashDisplay.value);
111+
const originalText = setupStatus.textContent;
112+
setupStatus.textContent = 'Hash copied to clipboard!';
113+
setTimeout(() => setupStatus.textContent = originalText, 2000);
114+
});
115+
116+
copyHeaderHashBtn.addEventListener('click', () => {
117+
navigator.clipboard.writeText(headerHashText.textContent || '');
118+
const originalText = setupStatus.textContent;
119+
setupStatus.textContent = 'Hash copied to clipboard!';
120+
setTimeout(() => setupStatus.textContent = originalText, 2000);
121+
});
122+
123+
async function checkExistingUsers() {
124+
try {
125+
const users = await chat.getUsersInChannel();
126+
if (users && users.length > 1) {
127+
chatHeader.classList.add('active');
128+
participantInfo.textContent = 'Peer is already here. Communication is encrypted.';
129+
}
130+
} catch (err) {
131+
console.error('Error checking users:', err);
132+
}
133+
}
134+
135+
function updateUrlHash(hash: string) {
136+
if (hash) {
137+
window.location.hash = hash;
138+
}
139+
}
140+
141+
function handleUrlHash() {
142+
const hash = window.location.hash.replace('#', '');
143+
if (hash && hash.length > 5) {
144+
hashInput.value = hash;
145+
showView('join');
146+
}
147+
}
148+
149+
joinBtn.addEventListener('click', async () => {
150+
// Determine which hash to use
151+
const enteredHash = hashInput.value.trim();
152+
const finalHash = enteredHash || channelHash;
153+
154+
if (!finalHash) {
155+
setupStatus.textContent = 'Please enter or generate a hash.';
156+
return;
157+
}
158+
159+
// Auto-generate User ID
160+
if (!userId) {
161+
userId = (utils as any).generateUUID();
162+
}
163+
164+
try {
165+
joinBtn.disabled = true;
166+
setupStatus.textContent = 'Connecting...';
167+
await chat.setChannel(finalHash, userId);
168+
169+
// Update UI with Hash
170+
headerHashText.textContent = finalHash;
171+
headerHashDisplay.classList.remove('hidden');
172+
updateUrlHash(finalHash);
173+
174+
setupOverlay.classList.add('hidden');
175+
chatContainer.classList.remove('hidden');
176+
177+
setupChatListeners();
178+
await checkExistingUsers();
179+
} catch (err) {
180+
console.error('Join error:', err);
181+
setupStatus.textContent = 'Failed to connect.';
182+
joinBtn.disabled = false;
183+
}
184+
});
185+
186+
function setupChatListeners() {
187+
chat.on('on-alice-join', () => {
188+
chatHeader.classList.add('active');
189+
participantInfo.textContent = 'Peer joined. Communication is encrypted.';
190+
});
191+
192+
chat.on('on-alice-disconnect', () => {
193+
chatHeader.classList.remove('active');
194+
participantInfo.textContent = 'Peer disconnected.';
195+
});
196+
197+
chat.on('chat-message', async (msg: any) => {
198+
const plainText = await (utils as any).decryptMessage(msg.message, privateKey);
199+
appendMessage(msg.sender, plainText, 'received');
200+
});
201+
202+
chat.on('call-added', (call: any) => {
203+
showCallOverlay('Incoming Call...');
204+
setupCallListeners(call);
205+
});
206+
}
207+
208+
// Messaging
209+
async function sendMessage() {
210+
const text = msgInput.value.trim();
211+
if (!text) return;
212+
213+
msgInput.value = '';
214+
appendMessage(userId, text, 'sent');
215+
216+
try {
217+
await chat.encrypt({ text }).send();
218+
} catch (err) {
219+
console.error('Send error:', err);
220+
}
221+
}
222+
223+
sendBtn.addEventListener('click', sendMessage);
224+
msgInput.addEventListener('keypress', (e) => {
225+
if (e.key === 'Enter') sendMessage();
226+
});
227+
228+
function appendMessage(sender: string, text: string, type: 'sent' | 'received') {
229+
const msgEl = document.createElement('div');
230+
msgEl.className = `message ${type}`;
231+
232+
const time = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
233+
234+
msgEl.innerHTML = `
235+
<div class="message-text">${text}</div>
236+
<div class="message-meta">
237+
<span>${sender}</span>
238+
<span>${time}</span>
239+
</div>
240+
`;
241+
242+
messagesArea.appendChild(msgEl);
243+
messagesArea.scrollTop = messagesArea.scrollHeight;
244+
}
245+
246+
// Calling
247+
let callTimer: any = null;
248+
let callStartTime: number = 0;
249+
250+
startCallBtn.addEventListener('click', async () => {
251+
try {
252+
const call = await chat.startCall();
253+
showCallOverlay('Calling...');
254+
setupCallListeners(call);
255+
} catch (err: any) {
256+
alert(err.message);
257+
}
258+
});
259+
260+
function setupCallListeners(call: any) {
261+
call.on('state-changed', (state: string) => {
262+
callStatusText.textContent = state.charAt(0).toUpperCase() + state.slice(1);
263+
264+
if (state === 'connected') {
265+
startTimer();
266+
}
267+
268+
if (state === 'closed' || state === 'failed') {
269+
hideCallOverlay();
270+
stopTimer();
271+
}
272+
});
273+
274+
endCallBtn.onclick = async () => {
275+
await call.endCall();
276+
hideCallOverlay();
277+
stopTimer();
278+
};
279+
}
280+
281+
function startTimer() {
282+
stopTimer();
283+
callStartTime = Date.now();
284+
callTimer = setInterval(() => {
285+
const seconds = Math.floor((Date.now() - callStartTime) / 1000);
286+
const m = Math.floor(seconds / 60).toString().padStart(2, '0');
287+
const s = (seconds % 60).toString().padStart(2, '0');
288+
callDuration.textContent = `${m}:${s}`;
289+
}, 1000);
290+
}
291+
292+
function stopTimer() {
293+
if (callTimer) clearInterval(callTimer);
294+
callDuration.textContent = '00:00';
295+
}
296+
297+
function showCallOverlay(status: string) {
298+
callOverlay.classList.remove('hidden');
299+
callStatusText.textContent = status;
300+
}
301+
302+
function hideCallOverlay() {
303+
callOverlay.classList.add('hidden');
304+
}
305+
306+
// Start
307+
initChat();

0 commit comments

Comments
 (0)