@pdc-test/chat-io 1.1.1 → 1.1.2

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,20 @@
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
+ if (type === 'ding') {
13
+ exec(`powershell -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Notify Email.wav').PlaySync();`);
14
+ } else if (type === 'msg') {
15
+ exec(`powershell -c (New-Object Media.SoundPlayer 'C:\\Windows\\Media\\Windows Proximity Notification.wav').PlaySync();`);
16
+ }
17
+ }
4
18
 
5
19
  // ============================================
6
20
  // CLIENTE MODULAR RÁPIDO (Carga NATIVA JSON)
@@ -33,7 +47,7 @@ function clearTopLine() {
33
47
  }
34
48
 
35
49
  // Interfaz del Teclado Local
36
- const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear'];
50
+ const commands = ['/users', '/flip', '/rps', '/tiendita', '/help', '/w', '/all', '/blink', '/exit', '/clear', '/sound', '/v', '/version'];
37
51
  let knownUsersList = [];
38
52
 
39
53
  function completer(line) {
@@ -148,7 +162,7 @@ ws.on('message', (data) => {
148
162
  break;
149
163
 
150
164
  case "ding":
151
- process.stdout.write("\x07"); // ASCII Bell físico disparado remotamente
165
+ playSound('ding');
152
166
  break;
153
167
 
154
168
  case "users_list":
@@ -161,8 +175,10 @@ ws.on('message', (data) => {
161
175
  if (res.isWhisper) {
162
176
  const dir = res.from === myName ? `Private → ${res.to}` : `${res.emoji} Secreto de ${res.from}`;
163
177
  printMessage(`\n[${getTime()}] 🔒 [${dir}]: \x1b[35m${safeMsg}\x1b[0m`);
178
+ if (res.from !== myName) playSound('ding');
164
179
  } else {
165
180
  printMessage(`\n[${getTime()}] 🌍 [${res.emoji} ${res.from}]: ${safeMsg}`);
181
+ if (res.from !== myName) playSound('msg');
166
182
  }
167
183
  break;
168
184
 
@@ -237,6 +253,15 @@ rl.on('line', (input) => {
237
253
  }
238
254
 
239
255
  // Local Helper Menú
256
+ if (line.toLowerCase() === "/version" || line.toLowerCase() === "/v") {
257
+ printMessage(`\nℹ️ Versión actual de Chat-IO: \x1b[1m\x1b[33m${pkgVersion}\x1b[0m\n`);
258
+ return;
259
+ }
260
+ if (line.toLowerCase().startsWith("/sound")) {
261
+ soundsEnabled = !soundsEnabled;
262
+ printMessage(`\n🔊 Sonidos ahora están: \x1b[1m\x1b[33m${soundsEnabled ? "ACTIVADOS" : "DESACTIVADOS"}\x1b[0m\n`);
263
+ return;
264
+ }
240
265
  if (line.toLowerCase() === "/clear") { console.clear(); rl.setPrompt('> '); rl.prompt(true); return; }
241
266
  if (line.toLowerCase() === "/exit") {
242
267
  printMessage("\x1b[33mSaliendo...\x1b[0m");
@@ -253,6 +278,8 @@ rl.on('line', (input) => {
253
278
  🌍 /all → Volver a la Sala Global Abierta
254
279
  🏪 /tiendita → Letrero de Neón de colores acelerado
255
280
  🧹 /clear → Limpia historial de consola
281
+ 🔊 /sound → Activa y desactiva notificaciones y sonidos
282
+ 🏷️ /version → Version del producto
256
283
  ❌ /exit → Salir del chat
257
284
  ℹ️ /help → Te ayuda desde la memoria Caché
258
285
  ─────────────────────────────────────────────\n`);
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.2",
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.2",
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
  }