@mulingai-npm/redis 3.40.26 → 3.40.28

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.
@@ -159,6 +159,13 @@ export declare class MulingstreamChunkManager {
159
159
  * Update SmartTranslate buffering metadata on a chunk (Section 22).
160
160
  * Writes `bufferStatus`, `pendingText`, and `consumedChunkNumbers` so the chunk row
161
161
  * persisted at the end of the pipeline reflects whether it was DEFERRED / USED / EMITTED.
162
+ *
163
+ * IMPORTANT — this is a partial HSET that touches ONLY the buffering fields.
164
+ * It deliberately does NOT use `withChunk()` (which rewrites the whole chunk hash)
165
+ * because handleTtsService can update `tts` concurrently with this call. Using the
166
+ * read-modify-write pattern of withChunk would race with TTS status updates and
167
+ * clobber `tts.<lang>.status = READY` back to INIT — preventing the audio sequencer
168
+ * from emitting the listener feed (audio came through as text-only with audio:"").
162
169
  */
163
170
  setBufferStatus(roomId: string, n: number, opt: {
164
171
  bufferStatus?: 'EMITTED' | 'DEFERRED' | 'USED';
@@ -45,7 +45,11 @@ class MulingstreamChunkManager {
45
45
  llmWords: h.llmWords ? this.deserialize(h.llmWords) : undefined,
46
46
  transcriptionSource: h.transcriptionSource || 'stt',
47
47
  routeUsed: h.routeUsed || undefined,
48
- sttHistory: h.sttHistory ? this.deserialize(h.sttHistory) : undefined
48
+ sttHistory: h.sttHistory ? this.deserialize(h.sttHistory) : undefined,
49
+ // SmartTranslate buffering (Section 22)
50
+ bufferStatus: h.bufferStatus || undefined,
51
+ pendingText: h.pendingText || undefined,
52
+ consumedChunkNumbers: h.consumedChunkNumbers ? this.deserialize(h.consumedChunkNumbers) : undefined
49
53
  };
50
54
  }
51
55
  getTimeout() {
@@ -240,6 +244,13 @@ class MulingstreamChunkManager {
240
244
  updateHash.routeUsed = chunk.routeUsed;
241
245
  if (chunk.sttHistory !== undefined)
242
246
  updateHash.sttHistory = this.serialize(chunk.sttHistory);
247
+ // SmartTranslate buffering (Section 22)
248
+ if (chunk.bufferStatus !== undefined)
249
+ updateHash.bufferStatus = chunk.bufferStatus;
250
+ if (chunk.pendingText !== undefined)
251
+ updateHash.pendingText = chunk.pendingText;
252
+ if (chunk.consumedChunkNumbers !== undefined)
253
+ updateHash.consumedChunkNumbers = this.serialize(chunk.consumedChunkNumbers);
243
254
  p.hset(key, updateHash);
244
255
  p.expire(key, EXPIRATION);
245
256
  await p.exec();
@@ -346,16 +357,36 @@ class MulingstreamChunkManager {
346
357
  * Update SmartTranslate buffering metadata on a chunk (Section 22).
347
358
  * Writes `bufferStatus`, `pendingText`, and `consumedChunkNumbers` so the chunk row
348
359
  * persisted at the end of the pipeline reflects whether it was DEFERRED / USED / EMITTED.
360
+ *
361
+ * IMPORTANT — this is a partial HSET that touches ONLY the buffering fields.
362
+ * It deliberately does NOT use `withChunk()` (which rewrites the whole chunk hash)
363
+ * because handleTtsService can update `tts` concurrently with this call. Using the
364
+ * read-modify-write pattern of withChunk would race with TTS status updates and
365
+ * clobber `tts.<lang>.status = READY` back to INIT — preventing the audio sequencer
366
+ * from emitting the listener feed (audio came through as text-only with audio:"").
349
367
  */
350
368
  async setBufferStatus(roomId, n, opt) {
351
- return this.withChunk(roomId, n, (c) => {
352
- if (opt.bufferStatus !== undefined)
353
- c.bufferStatus = opt.bufferStatus;
354
- if (opt.pendingText !== undefined)
355
- c.pendingText = opt.pendingText;
356
- if (opt.consumedChunkNumbers !== undefined)
357
- c.consumedChunkNumbers = opt.consumedChunkNumbers;
358
- });
369
+ const cid = await this.getChunkId(roomId, n);
370
+ if (!cid)
371
+ return null;
372
+ const key = this.chunkHashKey(cid);
373
+ const update = {};
374
+ if (opt.bufferStatus !== undefined)
375
+ update.bufferStatus = opt.bufferStatus;
376
+ if (opt.pendingText !== undefined)
377
+ update.pendingText = opt.pendingText;
378
+ if (opt.consumedChunkNumbers !== undefined)
379
+ update.consumedChunkNumbers = this.serialize(opt.consumedChunkNumbers);
380
+ if (Object.keys(update).length === 0) {
381
+ // Nothing to write — read-only fetch for callers that still want the chunk back.
382
+ return this.getMulingstreamChunkById(roomId, n);
383
+ }
384
+ const pipe = this.redisClient.pipeline();
385
+ pipe.hset(key, update);
386
+ pipe.expire(key, EXPIRATION);
387
+ await pipe.exec();
388
+ // Return the freshly-read chunk so callers can persist it (e.g. insertChunk to PG).
389
+ return this.getMulingstreamChunkById(roomId, n);
359
390
  }
360
391
  async areTranslationsProcessed(roomId, n) {
361
392
  const c = await this.getMulingstreamChunkById(roomId, n);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulingai-npm/redis",
3
- "version": "3.40.26",
3
+ "version": "3.40.28",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {