@shaxpir/duiduidui-models 1.20.1 → 1.24.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.
@@ -2,7 +2,9 @@ import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDateTime, MultiTime } from '@shaxpir/shaxpir-common';
3
3
  import { ShareSync } from '../repo';
4
4
  import { ArrayView } from './ArrayView';
5
- import { Content, ContentBody, ContentId, ContentMeta } from './Content';
5
+ import { ContentBody, ContentId, ContentMeta } from './Content';
6
+ import { SharedContent } from './SharedContent';
7
+ import { SocialUser } from './Social';
6
8
  export interface TextBlock {
7
9
  type: 'text';
8
10
  text: string;
@@ -43,6 +45,7 @@ export interface ChatMessage {
43
45
  role: 'user' | 'assistant';
44
46
  content: ContentBlock[];
45
47
  timestamp: CompactDateTime;
48
+ sender_id?: ContentId;
46
49
  system_prompt_hash?: string;
47
50
  model?: string;
48
51
  usage?: ChatUsage;
@@ -60,32 +63,62 @@ export interface ChatScratchpad {
60
63
  export interface ChatStub {
61
64
  id: ContentId;
62
65
  title?: string;
66
+ participants: SocialUser[];
63
67
  last_message_preview?: string;
64
68
  updated_at: CompactDateTime;
69
+ has_unread: {
70
+ [user_id: string]: boolean;
71
+ };
72
+ }
73
+ export type ChatStatus = 'idle' | 'pending' | 'error';
74
+ export interface ChatError {
75
+ message: string;
76
+ code?: string;
77
+ retryable: boolean;
65
78
  }
66
79
  export interface ChatPayload {
67
80
  title?: string;
81
+ participants: SocialUser[];
68
82
  messages: ChatMessage[];
69
- scratchpad: ChatScratchpad;
83
+ last_read: {
84
+ [user_id: string]: CompactDateTime;
85
+ };
86
+ status: ChatStatus;
87
+ error?: ChatError;
70
88
  }
71
89
  export interface ChatBody extends ContentBody {
72
90
  meta: ContentMeta;
73
91
  payload: ChatPayload;
74
92
  }
75
- export declare class Chat extends Content {
93
+ export declare class Chat extends SharedContent {
76
94
  private _messagesView;
95
+ private _participantsView;
77
96
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
78
97
  static makeChatId(userId: ContentId, chatKey: string): ContentId;
79
- static createDefaultPayload(): ChatPayload;
80
- static create(userId: ContentId, chatKey: string, payload?: ChatPayload, createdAt?: MultiTime): Chat;
98
+ static create(userId: ContentId, chatKey: string, participants: SocialUser[], createdAt?: MultiTime): Chat;
99
+ getAllSharedUserIds(): ContentId[];
100
+ /**
101
+ * Override to update manifests for all participants (via SharedContent)
102
+ * and update workspace chat stubs for each participant.
103
+ */
104
+ modelUpdated(): Promise<void>;
81
105
  get payload(): ChatPayload;
82
106
  get title(): string | undefined;
107
+ get participants(): ArrayView<SocialUser>;
83
108
  get messages(): ArrayView<ChatMessage>;
84
- get scratchpad(): ChatScratchpad;
109
+ get lastRead(): {
110
+ [user_id: string]: CompactDateTime;
111
+ };
112
+ get status(): ChatStatus;
113
+ get error(): ChatError | undefined;
85
114
  setTitle(title: string): void;
86
- setScratchpad(scratchpad: ChatScratchpad): void;
87
- updateScratchpadField(key: string, value: any): void;
88
- clearScratchpad(): void;
115
+ setStatus(status: ChatStatus): void;
116
+ setError(error: ChatError): void;
117
+ clearError(): void;
118
+ addParticipant(user: SocialUser): void;
119
+ removeParticipant(userId: ContentId): void;
120
+ markRead(userId: ContentId): void;
121
+ hasUnread(userId: ContentId): boolean;
89
122
  toStub(): ChatStub;
90
123
  appendMessage(message: ChatMessage): void;
91
124
  setBreakpoint(messageIndex: number, ttl: 'ephemeral' | 'standard'): void;
@@ -4,30 +4,24 @@ exports.Chat = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
5
  const repo_1 = require("../repo");
6
6
  const ArrayView_1 = require("./ArrayView");
7
- const Content_1 = require("./Content");
8
7
  const ContentKind_1 = require("./ContentKind");
9
8
  const Operation_1 = require("./Operation");
9
+ const SharedContent_1 = require("./SharedContent");
10
10
  // ---- Chat model ----
11
- class Chat extends Content_1.Content {
11
+ class Chat extends SharedContent_1.SharedContent {
12
12
  constructor(doc, shouldAcquire, shareSync) {
13
13
  super(doc, shouldAcquire, shareSync);
14
14
  this._messagesView = new ArrayView_1.ArrayView(this, ['payload', 'messages']);
15
+ this._participantsView = new ArrayView_1.ArrayView(this, ['payload', 'participants']);
15
16
  }
16
17
  // ---- ID generation ----
17
18
  static makeChatId(userId, chatKey) {
18
19
  return shaxpir_common_1.CachingHasher.makeMd5Base62Hash(`${ContentKind_1.ContentKind.CHAT}-${userId}-${chatKey}`);
19
20
  }
20
21
  // ---- Factory ----
21
- static createDefaultPayload() {
22
- return {
23
- messages: [],
24
- scratchpad: {},
25
- };
26
- }
27
- static create(userId, chatKey, payload, createdAt) {
22
+ static create(userId, chatKey, participants, createdAt) {
28
23
  const now = shaxpir_common_1.ClockService.getClock().now();
29
24
  createdAt ??= now;
30
- payload ??= Chat.createDefaultPayload();
31
25
  const chatId = Chat.makeChatId(userId, chatKey);
32
26
  return repo_1.ShareSyncFactory.get().createContent({
33
27
  meta: {
@@ -38,9 +32,46 @@ class Chat extends Content_1.Content {
38
32
  created_at: createdAt,
39
33
  updated_at: createdAt
40
34
  },
41
- payload
35
+ payload: {
36
+ participants,
37
+ messages: [],
38
+ last_read: {},
39
+ status: 'idle',
40
+ }
42
41
  });
43
42
  }
43
+ // ---- SharedContent implementation ----
44
+ getAllSharedUserIds() {
45
+ return this._participantsView.values.map(p => p.user_id);
46
+ }
47
+ /**
48
+ * Override to update manifests for all participants (via SharedContent)
49
+ * and update workspace chat stubs for each participant.
50
+ */
51
+ async modelUpdated() {
52
+ this.checkDisposed('Chat.modelUpdated');
53
+ // Update manifests for all participants
54
+ await super.modelUpdated();
55
+ // Update workspace stubs for all participants
56
+ const stub = this.toStub();
57
+ const userIds = this.getAllSharedUserIds();
58
+ for (const userId of userIds) {
59
+ try {
60
+ const workspaceId = shaxpir_common_1.CachingHasher.makeMd5Base62Hash(userId + "-" + ContentKind_1.ContentKind.WORKSPACE);
61
+ const workspace = this.shareSync.load(ContentKind_1.ContentKind.WORKSPACE, workspaceId);
62
+ if (workspace) {
63
+ await workspace.acquire();
64
+ if (workspace.exists()) {
65
+ workspace.upsertChatStub(stub);
66
+ }
67
+ workspace.release();
68
+ }
69
+ }
70
+ catch {
71
+ // Workspace may not exist yet for this user
72
+ }
73
+ }
74
+ }
44
75
  // ---- Getters ----
45
76
  get payload() {
46
77
  return this.doc.data.payload;
@@ -49,13 +80,25 @@ class Chat extends Content_1.Content {
49
80
  this.checkDisposed('Chat.title');
50
81
  return this.payload.title;
51
82
  }
83
+ get participants() {
84
+ this.checkDisposed('Chat.participants');
85
+ return this._participantsView;
86
+ }
52
87
  get messages() {
53
88
  this.checkDisposed('Chat.messages');
54
89
  return this._messagesView;
55
90
  }
56
- get scratchpad() {
57
- this.checkDisposed('Chat.scratchpad');
58
- return this.payload.scratchpad;
91
+ get lastRead() {
92
+ this.checkDisposed('Chat.lastRead');
93
+ return this.payload.last_read;
94
+ }
95
+ get status() {
96
+ this.checkDisposed('Chat.status');
97
+ return this.payload.status;
98
+ }
99
+ get error() {
100
+ this.checkDisposed('Chat.error');
101
+ return this.payload.error;
59
102
  }
60
103
  // ---- Setters ----
61
104
  setTitle(title) {
@@ -64,24 +107,57 @@ class Chat extends Content_1.Content {
64
107
  batch.setPathValue(['payload', 'title'], title);
65
108
  batch.commit();
66
109
  }
67
- setScratchpad(scratchpad) {
68
- this.checkDisposed('Chat.setScratchpad');
110
+ setStatus(status) {
111
+ this.checkDisposed('Chat.setStatus');
69
112
  const batch = new Operation_1.BatchOperation(this);
70
- batch.setPathValue(['payload', 'scratchpad'], scratchpad);
113
+ batch.setPathValue(['payload', 'status'], status);
71
114
  batch.commit();
72
115
  }
73
- updateScratchpadField(key, value) {
74
- this.checkDisposed('Chat.updateScratchpadField');
116
+ setError(error) {
117
+ this.checkDisposed('Chat.setError');
75
118
  const batch = new Operation_1.BatchOperation(this);
76
- batch.setPathValue(['payload', 'scratchpad', key], value);
119
+ batch.setPathValue(['payload', 'status'], 'error');
120
+ batch.setPathValue(['payload', 'error'], error);
77
121
  batch.commit();
78
122
  }
79
- clearScratchpad() {
80
- this.checkDisposed('Chat.clearScratchpad');
123
+ clearError() {
124
+ this.checkDisposed('Chat.clearError');
125
+ const batch = new Operation_1.BatchOperation(this);
126
+ batch.setPathValue(['payload', 'status'], 'idle');
127
+ batch.removeValueAtPath(['payload', 'error']);
128
+ batch.commit();
129
+ }
130
+ // ---- Participant operations ----
131
+ addParticipant(user) {
132
+ this.checkDisposed('Chat.addParticipant');
133
+ const exists = this._participantsView.firstIndexWhere(p => p.user_id === user.user_id) >= 0;
134
+ if (!exists) {
135
+ this._participantsView.push(user);
136
+ }
137
+ }
138
+ removeParticipant(userId) {
139
+ this.checkDisposed('Chat.removeParticipant');
140
+ this._participantsView.removeFirstWhere(p => p.user_id === userId);
141
+ }
142
+ // ---- Read tracking ----
143
+ markRead(userId) {
144
+ this.checkDisposed('Chat.markRead');
145
+ const now = shaxpir_common_1.ClockService.getClock().utc();
81
146
  const batch = new Operation_1.BatchOperation(this);
82
- batch.setPathValue(['payload', 'scratchpad'], {});
147
+ batch.setPathValue(['payload', 'last_read', userId], now);
83
148
  batch.commit();
84
149
  }
150
+ hasUnread(userId) {
151
+ this.checkDisposed('Chat.hasUnread');
152
+ const lastRead = this.payload.last_read[userId];
153
+ if (!lastRead)
154
+ return this._messagesView.length > 0;
155
+ const msgs = this._messagesView.values;
156
+ if (msgs.length === 0)
157
+ return false;
158
+ const lastMessageTimestamp = msgs[msgs.length - 1].timestamp;
159
+ return shaxpir_common_1.Time.isDateTimeAfter(lastMessageTimestamp, lastRead);
160
+ }
85
161
  // ---- Stub generation ----
86
162
  toStub() {
87
163
  this.checkDisposed('Chat.toStub');
@@ -94,11 +170,18 @@ class Chat extends Content_1.Content {
94
170
  preview = textBlock.text.slice(0, 100);
95
171
  }
96
172
  }
173
+ const has_unread = {};
174
+ for (let i = 0; i < this._participantsView.length; i++) {
175
+ const participant = this._participantsView.get(i);
176
+ has_unread[participant.user_id] = this.hasUnread(participant.user_id);
177
+ }
97
178
  return {
98
179
  id: this.id,
99
180
  title: this.title,
181
+ participants: this.participants.values,
100
182
  last_message_preview: preview,
101
183
  updated_at: this.updatedAt.utc_time,
184
+ has_unread,
102
185
  };
103
186
  }
104
187
  // ---- Message operations ----
@@ -1,7 +1,7 @@
1
1
  import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDateTime, DispatchTopic } from '@shaxpir/shaxpir-common';
3
3
  import { ShareSync } from '../repo';
4
- import { ContentId, ContentMeta, ContentRef } from "./Content";
4
+ import { ContentBody, ContentId, ContentRef } from "./Content";
5
5
  import { ContentKind } from './ContentKind';
6
6
  import { ManifestBody } from './Manifest';
7
7
  import { PermissionType } from './Permissions';
@@ -40,6 +40,6 @@ export declare abstract class Model {
40
40
  ensureRecentData(minVersion: CompactDateTime): Promise<Model>;
41
41
  doesUserHavePermission(userId: ContentId, type: PermissionType): boolean;
42
42
  static doesUserHaveManifestPermission(data: ManifestBody, userId: ContentId, type: PermissionType): boolean;
43
- static doesUserHaveContentPermission(kind: ContentKind, meta: ContentMeta, userId: ContentId, type: PermissionType): boolean;
43
+ static doesUserHaveContentPermission(kind: ContentKind, body: ContentBody, userId: ContentId, type: PermissionType): boolean;
44
44
  private log;
45
45
  }
@@ -269,24 +269,27 @@ class Model {
269
269
  return Model.doesUserHaveManifestPermission(this.doc.data, userId, type);
270
270
  }
271
271
  else {
272
- // Content objects and checkpoints all have a PermissionsMeta
273
- const meta = this.doc.data.meta;
274
- return Model.doesUserHaveContentPermission(this.kind, meta, userId, type);
272
+ return Model.doesUserHaveContentPermission(this.kind, this.doc.data, userId, type);
275
273
  }
276
274
  }
277
275
  static doesUserHaveManifestPermission(data, userId, type) {
278
276
  return data.meta.owner === userId;
279
277
  }
280
- static doesUserHaveContentPermission(kind, meta, userId, type) {
281
- // Users are allowed to read any of their own content, but they are not allowed to write their User, Billing, or Social objects.
282
- if (meta.owner === userId) {
278
+ static doesUserHaveContentPermission(kind, body, userId, type) {
279
+ // Users are allowed to read any of their own content, but they are not allowed to write their User, Billing, Social, or Chat objects.
280
+ if (body.meta.owner === userId) {
283
281
  if (type === Permissions_1.PermissionType.READ) {
284
282
  return true;
285
283
  }
286
284
  else if (type === Permissions_1.PermissionType.WRITE) {
287
- return kind !== ContentKind_1.ContentKind.USER && kind !== ContentKind_1.ContentKind.BILLING && kind !== ContentKind_1.ContentKind.SOCIAL;
285
+ return kind !== ContentKind_1.ContentKind.USER && kind !== ContentKind_1.ContentKind.BILLING && kind !== ContentKind_1.ContentKind.SOCIAL && kind !== ContentKind_1.ContentKind.CHAT;
288
286
  }
289
287
  }
288
+ // Shared content: participants can read but not write (server-controlled).
289
+ if (kind === ContentKind_1.ContentKind.CHAT && type === Permissions_1.PermissionType.READ) {
290
+ const chatPayload = body.payload;
291
+ return chatPayload.participants.some(p => p.user_id === userId);
292
+ }
290
293
  // If all else fails, deny permission.
291
294
  return false;
292
295
  }
@@ -0,0 +1,30 @@
1
+ import { Doc } from '@shaxpir/sharedb/lib/client';
2
+ import { ContentId } from './Content';
3
+ import { Content } from './Content';
4
+ import { ShareSync } from '../repo';
5
+ /**
6
+ * Base class for content models that are shared between multiple users.
7
+ *
8
+ * Unlike Content (which updates only the owner's manifest), SharedContent
9
+ * updates the manifests of all users who have access to the model. This
10
+ * enables reactive sync for all participants.
11
+ *
12
+ * Subclasses must implement getAllSharedUserIds() to identify which users
13
+ * should receive manifest notifications when the model changes.
14
+ *
15
+ * SharedContent models are server-controlled: clients can READ them but
16
+ * not WRITE them directly. All mutations go through server endpoints.
17
+ */
18
+ export declare abstract class SharedContent extends Content {
19
+ constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
20
+ /**
21
+ * Return the user IDs of all users who should receive manifest
22
+ * notifications when this model changes.
23
+ */
24
+ abstract getAllSharedUserIds(): ContentId[];
25
+ /**
26
+ * Override modelUpdated to update manifests for ALL shared users,
27
+ * not just the owner.
28
+ */
29
+ modelUpdated(): Promise<void>;
30
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SharedContent = void 0;
4
+ const ContentKind_1 = require("./ContentKind");
5
+ const Content_1 = require("./Content");
6
+ const Manifest_1 = require("./Manifest");
7
+ /**
8
+ * Base class for content models that are shared between multiple users.
9
+ *
10
+ * Unlike Content (which updates only the owner's manifest), SharedContent
11
+ * updates the manifests of all users who have access to the model. This
12
+ * enables reactive sync for all participants.
13
+ *
14
+ * Subclasses must implement getAllSharedUserIds() to identify which users
15
+ * should receive manifest notifications when the model changes.
16
+ *
17
+ * SharedContent models are server-controlled: clients can READ them but
18
+ * not WRITE them directly. All mutations go through server endpoints.
19
+ */
20
+ class SharedContent extends Content_1.Content {
21
+ constructor(doc, shouldAcquire, shareSync) {
22
+ super(doc, shouldAcquire, shareSync);
23
+ }
24
+ /**
25
+ * Override modelUpdated to update manifests for ALL shared users,
26
+ * not just the owner.
27
+ */
28
+ async modelUpdated() {
29
+ this.checkDisposed("SharedContent.modelUpdated");
30
+ this.acquire();
31
+ const userIds = this.getAllSharedUserIds();
32
+ for (const userId of userIds) {
33
+ const manifestId = Manifest_1.Manifest.makeManifestId(userId);
34
+ const manifest = this.shareSync.load(ContentKind_1.ContentKind.MANIFEST, manifestId);
35
+ if (manifest) {
36
+ await manifest.acquire();
37
+ manifest.update(this);
38
+ manifest.release();
39
+ }
40
+ }
41
+ this.release();
42
+ }
43
+ }
44
+ exports.SharedContent = SharedContent;
@@ -2,7 +2,7 @@ import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDate, CompactDateTime, MultiTime } from "@shaxpir/shaxpir-common";
3
3
  import { ShareSync } from '../repo';
4
4
  import { ArrayView } from './ArrayView';
5
- import { ChatStub } from './Chat';
5
+ import { ChatScratchpad, ChatStub } from './Chat';
6
6
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
7
7
  import { Conditions } from './Condition';
8
8
  import { Session } from './Session';
@@ -22,6 +22,9 @@ export interface WorkspacePayload {
22
22
  global_conditions: Conditions;
23
23
  uploaded_avatars: ContentId[];
24
24
  default_voice?: VoicePreference;
25
+ chat_scratchpads: {
26
+ [chatId: string]: ChatScratchpad;
27
+ };
25
28
  }
26
29
  export interface WorkspaceBody extends ContentBody {
27
30
  meta: ContentMeta;
@@ -56,6 +59,10 @@ export declare class Workspace extends Content {
56
59
  * we update its fields in place to avoid unnecessary churn.
57
60
  */
58
61
  upsertChatStub(stub: ChatStub): void;
62
+ getChatScratchpad(chatId: string): ChatScratchpad;
63
+ updateChatScratchpadText(chatId: string, text: string): void;
64
+ updateChatScratchpadField(chatId: string, key: string, value: any): void;
65
+ clearChatScratchpad(chatId: string): void;
59
66
  get devices(): ArrayView<ContentId>;
60
67
  get uploadedAvatars(): ArrayView<ContentId>;
61
68
  acquireSessionForUtcTime(utcTime: CompactDateTime): Promise<Session | null>;
@@ -56,6 +56,9 @@ class Workspace extends Content_1.Content {
56
56
  if (!Array.isArray(payload.uploaded_avatars)) {
57
57
  throw new Error('Workspace.create: payload.uploaded_avatars must be an array');
58
58
  }
59
+ if (!payload.chat_scratchpads || typeof payload.chat_scratchpads !== 'object' || Array.isArray(payload.chat_scratchpads)) {
60
+ throw new Error('Workspace.create: payload.chat_scratchpads must be an object');
61
+ }
59
62
  }
60
63
  static create(userId, payload) {
61
64
  Workspace.validatePayload(payload);
@@ -113,6 +116,36 @@ class Workspace extends Content_1.Content {
113
116
  this._chatsView.unshift(stub);
114
117
  }
115
118
  }
119
+ // ---- Chat scratchpads (per-user draft state, keyed by chat ID) ----
120
+ // Use empty string '' as the key for the "new chat" scratchpad.
121
+ getChatScratchpad(chatId) {
122
+ this.checkDisposed("Workspace.getChatScratchpad");
123
+ return this.payload.chat_scratchpads?.[chatId] || {};
124
+ }
125
+ updateChatScratchpadText(chatId, text) {
126
+ this.checkDisposed("Workspace.updateChatScratchpadText");
127
+ const batch = new Operation_1.BatchOperation(this);
128
+ batch.editPathText(['payload', 'chat_scratchpads', chatId, 'text'], text);
129
+ batch.commit();
130
+ }
131
+ updateChatScratchpadField(chatId, key, value) {
132
+ this.checkDisposed("Workspace.updateChatScratchpadField");
133
+ const batch = new Operation_1.BatchOperation(this);
134
+ batch.setPathValue(['payload', 'chat_scratchpads', chatId, key], value);
135
+ batch.commit();
136
+ }
137
+ clearChatScratchpad(chatId) {
138
+ this.checkDisposed("Workspace.clearChatScratchpad");
139
+ const path = ['payload', 'chat_scratchpads', chatId];
140
+ const current = this.payload.chat_scratchpads?.[chatId];
141
+ if (!current)
142
+ return;
143
+ const batch = new Operation_1.BatchOperation(this);
144
+ for (const key of Object.keys(current)) {
145
+ batch.removeValueAtPath([...path, key]);
146
+ }
147
+ batch.commit();
148
+ }
116
149
  // NOTE: As the user adds devices, we will always add new devices to the end of the array.
117
150
  // So the most-recently-added device will always be at the end.
118
151
  get devices() {
@@ -26,6 +26,7 @@ export * from './RecordType';
26
26
  export * from './Review';
27
27
  export * from './SearchState';
28
28
  export * from './Session';
29
+ export * from './SharedContent';
29
30
  export * from './SkillLevel';
30
31
  export * from './Social';
31
32
  export * from './Streaks';
@@ -43,6 +43,7 @@ __exportStar(require("./RecordType"), exports);
43
43
  __exportStar(require("./Review"), exports);
44
44
  __exportStar(require("./SearchState"), exports);
45
45
  __exportStar(require("./Session"), exports);
46
+ __exportStar(require("./SharedContent"), exports);
46
47
  __exportStar(require("./SkillLevel"), exports);
47
48
  __exportStar(require("./Social"), exports);
48
49
  __exportStar(require("./Streaks"), exports);
@@ -42,6 +42,7 @@ const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
42
42
  const reconnecting_websocket_1 = __importDefault(require("reconnecting-websocket"));
43
43
  const models_1 = require("../models");
44
44
  const Billing_1 = require("../models/Billing");
45
+ const Chat_1 = require("../models/Chat");
45
46
  const Collection_1 = require("../models/Collection");
46
47
  const Content_1 = require("../models/Content");
47
48
  const ContentKind_1 = require("../models/ContentKind");
@@ -478,6 +479,9 @@ class ShareSync {
478
479
  if (kind === ContentKind_1.ContentKind.BILLING) {
479
480
  return new Billing_1.Billing(doc, shouldAcquire, shareSync);
480
481
  }
482
+ else if (kind === ContentKind_1.ContentKind.CHAT) {
483
+ return new Chat_1.Chat(doc, shouldAcquire, shareSync);
484
+ }
481
485
  else if (kind === ContentKind_1.ContentKind.COLLECTION) {
482
486
  return new Collection_1.Collection(doc, shouldAcquire, shareSync);
483
487
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.20.1",
3
+ "version": "1.24.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"