@jupyter/chat 0.25.0-alpha.7 → 0.25.0-rc.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.
@@ -35,18 +35,16 @@ describe('writers state', () => {
35
35
  model.setWritingStatus(userA, { typingIndicator: 'x' });
36
36
  expect(changes.length).toBe(count);
37
37
  });
38
- it('auto-clears a writer after the timeout unless refreshed', () => {
38
+ it('keeps a writer until it is explicitly cleared (no auto-expiry)', () => {
39
39
  jest.useFakeTimers();
40
40
  try {
41
- model.setWritingStatus(userA, undefined, 2000);
41
+ model.setWritingStatus(userA);
42
42
  expect(model.writers).toHaveLength(1);
43
- // Refresh before expiry keeps it alive.
44
- jest.advanceTimersByTime(1500);
45
- model.setWritingStatus(userA, undefined, 2000);
46
- jest.advanceTimersByTime(1500);
43
+ // A single call persists like any other update: no timer drops it.
44
+ jest.advanceTimersByTime(60000);
47
45
  expect(model.writers).toHaveLength(1);
48
- // No refresh -> auto-cleared after the timeout (the WS anti-stuck path).
49
- jest.advanceTimersByTime(2000);
46
+ // Only an explicit clear removes it.
47
+ model.clearWritingStatus(userA);
50
48
  expect(model.writers).toHaveLength(0);
51
49
  }
52
50
  finally {
package/lib/model.d.ts CHANGED
@@ -169,14 +169,14 @@ export interface IChatModel extends IDisposable {
169
169
  /**
170
170
  * Mark a user as currently writing (add or update their writer entry).
171
171
  *
172
+ * The writer stays until explicitly removed via {@link clearWritingStatus}
173
+ * (or replaced by a new snapshot in {@link updateWriters}); there is no
174
+ * auto-expiry, so a single call persists like any other update.
175
+ *
172
176
  * @param user - the writing user.
173
177
  * @param status - optional writing status (messageID, custom typingIndicator).
174
- * @param timeout - optional auto-clear delay in ms. When set, the user is
175
- * automatically cleared after `timeout` unless refreshed by another call.
176
- * Used by transports without their own liveness signal (e.g. WebSocket) to
177
- * avoid a stuck "is typing" if a clear message is never received.
178
178
  */
179
- setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus, timeout?: number): void;
179
+ setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus): void;
180
180
  /**
181
181
  * Remove a user from the writers list.
182
182
  */
@@ -184,7 +184,7 @@ export interface IChatModel extends IDisposable {
184
184
  /**
185
185
  * Broadcast the *current user's* writing status to other clients, or clear it
186
186
  * with `null`. Implemented per transport (RTC sets awareness; WebSocket sends
187
- * a periodic writing frame). Default implementation is a no-op.
187
+ * a single writing frame). Default implementation is a no-op.
188
188
  */
189
189
  broadcastWritingStatus(status: IChatModel.IWritingStatus | null): void;
190
190
  /**
@@ -375,7 +375,7 @@ export declare abstract class AbstractChatModel implements IChatModel {
375
375
  /**
376
376
  * Mark a user as currently writing. See IChatModel.setWritingStatus.
377
377
  */
378
- setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus, timeout?: number): void;
378
+ setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus): void;
379
379
  /**
380
380
  * Remove a user from the writers list. See IChatModel.clearWritingStatus.
381
381
  */
@@ -386,8 +386,6 @@ export declare abstract class AbstractChatModel implements IChatModel {
386
386
  */
387
387
  broadcastWritingStatus(_status: IChatModel.IWritingStatus | null): void;
388
388
  private _removeWriter;
389
- private _clearWriterTimer;
390
- private _clearAllWriterTimers;
391
389
  /**
392
390
  * Create the chat context that will be passed to the input model.
393
391
  */
@@ -438,7 +436,6 @@ export declare abstract class AbstractChatModel implements IChatModel {
438
436
  private _documentManager;
439
437
  private _notificationId;
440
438
  private _writers;
441
- private _writerTimers;
442
439
  private _messageEditions;
443
440
  private _messagesUpdated;
444
441
  private _messageChanged;
package/lib/model.js CHANGED
@@ -30,7 +30,6 @@ export class AbstractChatModel {
30
30
  this._isDisposed = false;
31
31
  this._notificationId = null;
32
32
  this._writers = new Map();
33
- this._writerTimers = new Map();
34
33
  this._messageEditions = new Map();
35
34
  this._messagesUpdated = new Signal(this);
36
35
  this._messageChanged = new Signal(this);
@@ -402,9 +401,7 @@ export class AbstractChatModel {
402
401
  */
403
402
  updateWriters(writers) {
404
403
  // Reconcile the writers map with the provided snapshot (used by
405
- // snapshot-style transports such as RTC awareness). Any auto-clear timers
406
- // are dropped, since the snapshot is authoritative.
407
- this._clearAllWriterTimers();
404
+ // snapshot-style transports such as RTC awareness).
408
405
  const next = new Map();
409
406
  for (const writer of writers) {
410
407
  next.set(writer.user.username, writer);
@@ -417,16 +414,12 @@ export class AbstractChatModel {
417
414
  /**
418
415
  * Mark a user as currently writing. See IChatModel.setWritingStatus.
419
416
  */
420
- setWritingStatus(user, status, timeout) {
417
+ setWritingStatus(user, status) {
421
418
  const writer = {
422
419
  user,
423
420
  messageID: status === null || status === void 0 ? void 0 : status.messageID,
424
421
  typingIndicator: status === null || status === void 0 ? void 0 : status.typingIndicator
425
422
  };
426
- this._clearWriterTimer(user.username);
427
- if (timeout !== undefined) {
428
- this._writerTimers.set(user.username, window.setTimeout(() => this._removeWriter(user.username), timeout));
429
- }
430
423
  const previous = this._writers.get(user.username);
431
424
  this._writers.set(user.username, writer);
432
425
  if (!previous || !Private.writerEqual(previous, writer)) {
@@ -447,24 +440,10 @@ export class AbstractChatModel {
447
440
  // no-op by default
448
441
  }
449
442
  _removeWriter(username) {
450
- this._clearWriterTimer(username);
451
443
  if (this._writers.delete(username)) {
452
444
  this._writersChanged.emit(this.writers);
453
445
  }
454
446
  }
455
- _clearWriterTimer(username) {
456
- const timer = this._writerTimers.get(username);
457
- if (timer !== undefined) {
458
- window.clearTimeout(timer);
459
- this._writerTimers.delete(username);
460
- }
461
- }
462
- _clearAllWriterTimers() {
463
- for (const timer of this._writerTimers.values()) {
464
- window.clearTimeout(timer);
465
- }
466
- this._writerTimers.clear();
467
- }
468
447
  /**
469
448
  * Get the input model of the edited message, given its id.
470
449
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter/chat",
3
- "version": "0.25.0-alpha.7",
3
+ "version": "0.25.0-rc.0",
4
4
  "description": "A package that provides UI components that can be used to create a chat in a Jupyterlab extension.",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -47,20 +47,18 @@ describe('writers state', () => {
47
47
  expect(changes.length).toBe(count);
48
48
  });
49
49
 
50
- it('auto-clears a writer after the timeout unless refreshed', () => {
50
+ it('keeps a writer until it is explicitly cleared (no auto-expiry)', () => {
51
51
  jest.useFakeTimers();
52
52
  try {
53
- model.setWritingStatus(userA, undefined, 2000);
53
+ model.setWritingStatus(userA);
54
54
  expect(model.writers).toHaveLength(1);
55
55
 
56
- // Refresh before expiry keeps it alive.
57
- jest.advanceTimersByTime(1500);
58
- model.setWritingStatus(userA, undefined, 2000);
59
- jest.advanceTimersByTime(1500);
56
+ // A single call persists like any other update: no timer drops it.
57
+ jest.advanceTimersByTime(60_000);
60
58
  expect(model.writers).toHaveLength(1);
61
59
 
62
- // No refresh -> auto-cleared after the timeout (the WS anti-stuck path).
63
- jest.advanceTimersByTime(2000);
60
+ // Only an explicit clear removes it.
61
+ model.clearWritingStatus(userA);
64
62
  expect(model.writers).toHaveLength(0);
65
63
  } finally {
66
64
  jest.useRealTimers();
package/src/model.ts CHANGED
@@ -226,18 +226,14 @@ export interface IChatModel extends IDisposable {
226
226
  /**
227
227
  * Mark a user as currently writing (add or update their writer entry).
228
228
  *
229
+ * The writer stays until explicitly removed via {@link clearWritingStatus}
230
+ * (or replaced by a new snapshot in {@link updateWriters}); there is no
231
+ * auto-expiry, so a single call persists like any other update.
232
+ *
229
233
  * @param user - the writing user.
230
234
  * @param status - optional writing status (messageID, custom typingIndicator).
231
- * @param timeout - optional auto-clear delay in ms. When set, the user is
232
- * automatically cleared after `timeout` unless refreshed by another call.
233
- * Used by transports without their own liveness signal (e.g. WebSocket) to
234
- * avoid a stuck "is typing" if a clear message is never received.
235
235
  */
236
- setWritingStatus(
237
- user: IUser,
238
- status?: IChatModel.IWritingStatus,
239
- timeout?: number
240
- ): void;
236
+ setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus): void;
241
237
 
242
238
  /**
243
239
  * Remove a user from the writers list.
@@ -247,7 +243,7 @@ export interface IChatModel extends IDisposable {
247
243
  /**
248
244
  * Broadcast the *current user's* writing status to other clients, or clear it
249
245
  * with `null`. Implemented per transport (RTC sets awareness; WebSocket sends
250
- * a periodic writing frame). Default implementation is a no-op.
246
+ * a single writing frame). Default implementation is a no-op.
251
247
  */
252
248
  broadcastWritingStatus(status: IChatModel.IWritingStatus | null): void;
253
249
 
@@ -722,9 +718,7 @@ export abstract class AbstractChatModel implements IChatModel {
722
718
  */
723
719
  updateWriters(writers: IChatModel.IWriter[]): void {
724
720
  // Reconcile the writers map with the provided snapshot (used by
725
- // snapshot-style transports such as RTC awareness). Any auto-clear timers
726
- // are dropped, since the snapshot is authoritative.
727
- this._clearAllWriterTimers();
721
+ // snapshot-style transports such as RTC awareness).
728
722
  const next = new Map<string, IChatModel.IWriter>();
729
723
  for (const writer of writers) {
730
724
  next.set(writer.user.username, writer);
@@ -738,23 +732,12 @@ export abstract class AbstractChatModel implements IChatModel {
738
732
  /**
739
733
  * Mark a user as currently writing. See IChatModel.setWritingStatus.
740
734
  */
741
- setWritingStatus(
742
- user: IUser,
743
- status?: IChatModel.IWritingStatus,
744
- timeout?: number
745
- ): void {
735
+ setWritingStatus(user: IUser, status?: IChatModel.IWritingStatus): void {
746
736
  const writer: IChatModel.IWriter = {
747
737
  user,
748
738
  messageID: status?.messageID,
749
739
  typingIndicator: status?.typingIndicator
750
740
  };
751
- this._clearWriterTimer(user.username);
752
- if (timeout !== undefined) {
753
- this._writerTimers.set(
754
- user.username,
755
- window.setTimeout(() => this._removeWriter(user.username), timeout)
756
- );
757
- }
758
741
  const previous = this._writers.get(user.username);
759
742
  this._writers.set(user.username, writer);
760
743
  if (!previous || !Private.writerEqual(previous, writer)) {
@@ -778,27 +761,11 @@ export abstract class AbstractChatModel implements IChatModel {
778
761
  }
779
762
 
780
763
  private _removeWriter(username: string): void {
781
- this._clearWriterTimer(username);
782
764
  if (this._writers.delete(username)) {
783
765
  this._writersChanged.emit(this.writers);
784
766
  }
785
767
  }
786
768
 
787
- private _clearWriterTimer(username: string): void {
788
- const timer = this._writerTimers.get(username);
789
- if (timer !== undefined) {
790
- window.clearTimeout(timer);
791
- this._writerTimers.delete(username);
792
- }
793
- }
794
-
795
- private _clearAllWriterTimers(): void {
796
- for (const timer of this._writerTimers.values()) {
797
- window.clearTimeout(timer);
798
- }
799
- this._writerTimers.clear();
800
- }
801
-
802
769
  /**
803
770
  * Create the chat context that will be passed to the input model.
804
771
  */
@@ -914,7 +881,6 @@ export abstract class AbstractChatModel implements IChatModel {
914
881
  private _documentManager: IDocumentManager | null;
915
882
  private _notificationId: string | null = null;
916
883
  private _writers = new Map<string, IChatModel.IWriter>();
917
- private _writerTimers = new Map<string, number>();
918
884
  private _messageEditions = new Map<string, IInputModel>();
919
885
  private _messagesUpdated = new Signal<IChatModel, void>(this);
920
886
  private _messageChanged = new Signal<IChatModel, IMessage>(this);