@pdc-test/chat-io 1.1.1 → 1.1.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/bin/cli.js CHANGED
@@ -1,6 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  const WebSocket = require('ws');
3
3
  const readline = require('readline');
4
+ const { exec } = require('child_process');
5
+ const path = require('path');
6
+ const pkgVersion = require('../package.json').version;
7
+
8
+ let soundsEnabled = true;
9
+
10
+ function playSound(type) {
11
+ if (!soundsEnabled) return;
12
+ const opts = { windowsHide: true, stdio: 'ignore' };
13
+ if (type === 'ding') {
14
+ exec(`powershell -WindowStyle Hidden -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Notify Email.wav').PlaySync();`, opts);
15
+ } else if (type === 'msg') {
16
+ exec(`powershell -WindowStyle Hidden -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Proximity Notification.wav').PlaySync();`, opts);
17
+ }
18
+ }
4
19
 
5
20
  // ============================================
6
21
  // CLIENTE MODULAR RÁPIDO (Carga NATIVA JSON)
@@ -33,7 +48,7 @@ function clearTopLine() {
33
48
  }
34
49
 
35
50
  // Interfaz del Teclado Local
36
- const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear'];
51
+ const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear', '/sound', '/v', '/version'];
37
52
  let knownUsersList = [];
38
53
 
39
54
  function completer(line) {
@@ -148,7 +163,7 @@ ws.on('message', (data) => {
148
163
  break;
149
164
 
150
165
  case "ding":
151
- process.stdout.write("\x07"); // ASCII Bell físico disparado remotamente
166
+ playSound('ding');
152
167
  break;
153
168
 
154
169
  case "users_list":
@@ -161,8 +176,10 @@ ws.on('message', (data) => {
161
176
  if (res.isWhisper) {
162
177
  const dir = res.from === myName ? `Private → ${res.to}` : `${res.emoji} Secreto de ${res.from}`;
163
178
  printMessage(`\n[${getTime()}] 🔒 [${dir}]: \x1b[35m${safeMsg}\x1b[0m`);
179
+ if (res.from !== myName) playSound('ding');
164
180
  } else {
165
181
  printMessage(`\n[${getTime()}] 🌍 [${res.emoji} ${res.from}]: ${safeMsg}`);
182
+ if (res.from !== myName) playSound('msg');
166
183
  }
167
184
  break;
168
185
 
@@ -237,6 +254,15 @@ rl.on('line', (input) => {
237
254
  }
238
255
 
239
256
  // Local Helper Menú
257
+ if (line.toLowerCase() === "/version" || line.toLowerCase() === "/v") {
258
+ printMessage(`\nℹ️ Versión actual de Chat-IO: \x1b[1m\x1b[33m${pkgVersion}\x1b[0m\n`);
259
+ return;
260
+ }
261
+ if (line.toLowerCase().startsWith("/sound")) {
262
+ soundsEnabled = !soundsEnabled;
263
+ printMessage(`\n🔊 Sonidos ahora están: \x1b[1m\x1b[33m${soundsEnabled ? "ACTIVADOS" : "DESACTIVADOS"}\x1b[0m\n`);
264
+ return;
265
+ }
240
266
  if (line.toLowerCase() === "/clear") { console.clear(); rl.setPrompt('> '); rl.prompt(true); return; }
241
267
  if (line.toLowerCase() === "/exit") {
242
268
  printMessage("\x1b[33mSaliendo...\x1b[0m");
@@ -253,6 +279,8 @@ rl.on('line', (input) => {
253
279
  🌍 /all → Volver a la Sala Global Abierta
254
280
  🏪 /tiendita → Letrero de Neón de colores acelerado
255
281
  🧹 /clear → Limpia historial de consola
282
+ 🔊 /sound → Activa y desactiva notificaciones y sonidos
283
+ 🏷️ /version → Version del producto
256
284
  ❌ /exit → Salir del chat
257
285
  ℹ️ /help → Te ayuda desde la memoria Caché
258
286
  ─────────────────────────────────────────────\n`);
@@ -291,7 +319,7 @@ rl.on('line', (input) => {
291
319
  ws.send(JSON.stringify({ type: "chat", msg: line }));
292
320
  }
293
321
 
294
- isTyping = false;
322
+ currentIsTyping = false;
295
323
  ws.send(JSON.stringify({ type: "typing_stop" }));
296
324
  });
297
325
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdc-test/chat-io",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "main": "./src/index.js",
5
5
  "bin": {
6
6
  "chat-io": "bin/cli.js"
@@ -9,7 +9,7 @@
9
9
  "start": "node src/server/index.js"
10
10
  },
11
11
  "dependencies": {
12
- "@pdc-test/chat-io": "^1.1.1",
12
+ "@pdc-test/chat-io": "^1.1.3",
13
13
  "crypto-js": "^4.2.0",
14
14
  "ws": "^8.0.0"
15
15
  }
@@ -41,6 +41,7 @@ function getExactName(name) {
41
41
  }
42
42
 
43
43
  // State para Tiping
44
+ // typingMap trackea timeouts y a quién se le está escribiendo
44
45
  let typingMap = new Map();
45
46
 
46
47
  function broadcastUsers() {
@@ -56,8 +57,18 @@ function broadcastUsers() {
56
57
  }
57
58
 
58
59
  function broadcastTyping() {
59
- const list = Array.from(typingMap.keys());
60
- broadcast({ type: "typing_event", users: list });
60
+ for (const [s, data] of sessions.entries()) {
61
+ if (s.readyState === WebSocket.OPEN && data.name) {
62
+ const visibleTypers = [];
63
+ for (const [typerName, typeData] of typingMap.entries()) {
64
+ // Si está escribiendo en público (target == null) o le escribe directo a este usuario
65
+ if (!typeData.target || typeData.target.toLowerCase() === data.name.toLowerCase()) {
66
+ visibleTypers.push(typerName);
67
+ }
68
+ }
69
+ try { s.send(JSON.stringify({ type: "typing_event", users: visibleTypers })); } catch(e) {}
70
+ }
71
+ }
61
72
  }
62
73
 
63
74
  wss.on("connection", (ws) => {
@@ -97,7 +108,7 @@ wss.on("connection", (ws) => {
97
108
  // Limpiar typing automático si envía un mensaje real
98
109
  if (req.type === "chat" || req.type === "command") {
99
110
  if (typingMap.has(myName)) {
100
- clearTimeout(typingMap.get(myName));
111
+ clearTimeout(typingMap.get(myName).timer);
101
112
  typingMap.delete(myName);
102
113
  broadcastTyping();
103
114
  }
@@ -105,17 +116,20 @@ wss.on("connection", (ws) => {
105
116
 
106
117
  switch (req.type) {
107
118
  case "typing":
108
- if (typingMap.has(myName)) clearTimeout(typingMap.get(myName));
109
- typingMap.set(myName, setTimeout(() => {
110
- typingMap.delete(myName);
111
- broadcastTyping();
112
- }, 5000));
119
+ if (typingMap.has(myName)) clearTimeout(typingMap.get(myName).timer);
120
+ typingMap.set(myName, {
121
+ target: user.privateTarget,
122
+ timer: setTimeout(() => {
123
+ typingMap.delete(myName);
124
+ broadcastTyping();
125
+ }, 5000)
126
+ });
113
127
  broadcastTyping();
114
128
  break;
115
129
 
116
130
  case "typing_stop":
117
131
  if (typingMap.has(myName)) {
118
- clearTimeout(typingMap.get(myName));
132
+ clearTimeout(typingMap.get(myName).timer);
119
133
  typingMap.delete(myName);
120
134
  broadcastTyping();
121
135
  }
@@ -218,7 +232,7 @@ wss.on("connection", (ws) => {
218
232
  if (u && u.name) {
219
233
  broadcast({ type: "system", msg: `🔴 [\x1b[31m${u.emoji} ${u.name}\x1b[0m] abandonó la sala.` }, ws);
220
234
  if (typingMap.has(u.name)) {
221
- clearTimeout(typingMap.get(u.name));
235
+ clearTimeout(typingMap.get(u.name).timer);
222
236
  typingMap.delete(u.name);
223
237
  broadcastTyping(); // Notificamos de inmediato al mundo para que eliminen su typing UI
224
238
  }