@jsm-mit/chat-motoko-package 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -5,23 +5,30 @@ multi-project, multi-party chat on the Internet Computer — plus the integratio
5
5
  that prove it.
6
6
 
7
7
  ```ts
8
- import { ChatsActor, MessagesActor, ChatPoller } from "@jsm-mit/chat-motoko-package";
8
+ import { RoomsActor, ChatsActor, MessagesActor, ChatPoller } from "@jsm-mit/chat-motoko-package";
9
9
 
10
- const chats = new ChatsActor(canisterId, identity);
11
- const chat = await chats.createChatAsyncUnsafe({ projectId: "sultana-dev", subject: salonId, firstMessage: "cześć" });
10
+ // A project admin defines a room: who receives the customer's messages.
11
+ await new RoomsActor(canisterId, adminIdentity).createRoomAsyncUnsafe({
12
+ projectId: "sultana-stage", id: "assistant", name: "Asystent",
13
+ recipients: [{ principal: villagePrincipal, role: "agent", displayName: "Asystentka Ola" }],
14
+ });
15
+
16
+ // A customer opens the room — the same call returns the same chat next time.
17
+ const chat = await new ChatsActor(canisterId, identity).openChatAsyncUnsafe({ projectId: "sultana-stage", roomId: "assistant", customerName: "Michał" });
12
18
 
13
19
  const messages = new MessagesActor(canisterId, identity);
14
20
  await messages.postAsyncUnsafe({ chatId: chat.id, text: "dodaj usługę strzyżenie" });
15
21
  const page = await messages.getMessagesAsyncUnsafe({ chatId: chat.id, sinceSeq: 0 });
16
22
 
17
- // An agent host: every new message in every chat this identity belongs to.
23
+ // An agent host: every new message in every chat this identity is a recipient of, with
24
+ // the room and the customer on each message — route by (projectId, roomId).
18
25
  const poller = new ChatPoller(messages, 1000, { onError: console.error });
19
- poller.messages$.subscribe((m) => console.log(m.chatId, m.kind, m.text));
26
+ poller.messages$.subscribe((m) => console.log(m.roomId, m.customer, m.kind, m.text));
20
27
  poller.run();
21
28
  ```
22
29
 
23
- One class per canister controller (`AdminActor`, `ProjectsActor`, `ChatsActor`,
24
- `MessagesActor`), every method `…AsyncUnsafe` (throws one of `CanisterError`,
30
+ One class per canister controller (`AdminActor`, `ProjectsActor`, `RoomsActor`,
31
+ `ChatsActor`, `MessagesActor`), every method `…AsyncUnsafe` (throws one of `CanisterError`,
25
32
  `CriticalCanisterError`, `CallRefusedAtInspectionStage`) or `…AsyncSafe` (never
26
33
  throws). Views translate `Principal` → text, `opt` → optional, variants → string
27
34
  unions; sequence numbers are plain `number`s, timestamps `bigint` nanoseconds.
@@ -29,8 +36,11 @@ unions; sequence numbers are plain `number`s, timestamps `bigint` nanoseconds.
29
36
  `src/` is browser-safe — the same package serves the agent host and a web panel.
30
37
 
31
38
  Scripts: `build`, `typecheck`, `sync-declarations`, `test-suite`,
32
- `test-access-restrictions`, `sandbox` (an interactive admin/chat console:
33
- `npm run sandbox -- <canister-id>`). See `CLAUDE.md` for who runs what.
39
+ `test-access-restrictions`, `user1` / `user2` (an interactive admin/chat console, one
40
+ person per terminal: the key comes from `USER1_PEM` / `USER2_PEM` in `.env`; another
41
+ canister: `npm run user2 -- <canister-id>`), `redeploy` (build `../chat-motoko` and install it
42
+ on `CANISTER_ID` without tests; `npm run redeploy -- reinstall` or `-- upgrade`; after a
43
+ reinstall claim the admin role yourself in the sandbox). See `CLAUDE.md` for who runs what.
34
44
 
35
45
  ## Publishing
36
46
 
@@ -1,110 +1,128 @@
1
+ type UpdateRoomArgs =
2
+ record {
3
+ name: opt text;
4
+ projectId: ProjectId;
5
+ recipients: opt vec Recipient;
6
+ roomId: RoomId;
7
+ };
1
8
  type UpdateProjectArgs =
2
9
  record {
3
10
  admins: opt vec principal;
4
- agents: opt vec principal;
5
- agentsMayInvite: opt bool;
6
- defaultPolicy: opt Policy;
7
11
  projectId: ProjectId;
8
12
  };
9
- type SystemEvent =
10
- variant {
11
- chatClosed;
12
- chatCreated;
13
- memberInvited: record {
14
- by: principal;
15
- "principal": principal;
16
- role: Role;
17
- };
18
- memberJoined: record {
19
- "principal": principal;
20
- role: Role;
21
- };
22
- memberLeft: record {"principal": principal;};
23
- memberRemoved: record {
24
- by: principal;
25
- "principal": principal;
26
- };
27
- policyChanged: Policy;
28
- };
29
- type SetPolicyArgs =
13
+ type SystemEvent = variant {chatCreated;};
14
+ type SetQuotaLimitsArgs = record {limits: QuotaLimits;};
15
+ type SetLoggingEnabledArgs = record {enabled: bool;};
16
+ type RoomId = text;
17
+ type Room =
30
18
  record {
31
- chatId: ChatId;
32
- policy: Policy;
19
+ createdAt: int;
20
+ createdBy: principal;
21
+ id: RoomId;
22
+ name: text;
23
+ projectId: ProjectId;
24
+ recipients: vec Recipient;
33
25
  };
34
- type SetLoggingEnabledArgs = record {enabled: bool;};
35
26
  type Role =
36
27
  variant {
37
- admin;
38
28
  agent;
39
- member;
40
- owner;
29
+ customer;
30
+ worker;
41
31
  };
42
32
  type Result_9 =
43
33
  variant {
44
34
  err: Error;
45
- ok: vec principal;
35
+ ok: vec Project;
46
36
  };
47
37
  type Result_8 =
48
38
  variant {
49
39
  err: Error;
50
- ok: MessagesPage;
40
+ ok: vec Room;
51
41
  };
52
42
  type Result_7 =
53
43
  variant {
54
44
  err: Error;
55
- ok: vec Chat;
45
+ ok: Chat;
56
46
  };
57
47
  type Result_6 =
58
48
  variant {
59
49
  err: Error;
60
- ok: vec Project;
50
+ ok: PollResult;
61
51
  };
62
52
  type Result_5 =
63
53
  variant {
64
54
  err: Error;
65
- ok: PollResult;
55
+ ok: Message;
66
56
  };
67
57
  type Result_4 =
68
58
  variant {
69
59
  err: Error;
70
- ok: Message;
60
+ ok: principal;
71
61
  };
72
62
  type Result_3 =
73
63
  variant {
74
64
  err: Error;
75
- ok: principal;
65
+ ok: bool;
76
66
  };
77
67
  type Result_2 =
78
68
  variant {
79
69
  err: Error;
80
- ok: bool;
70
+ ok: QuotaLimits;
71
+ };
72
+ type Result_13 =
73
+ variant {
74
+ err: Error;
75
+ ok: vec principal;
76
+ };
77
+ type Result_12 =
78
+ variant {
79
+ err: Error;
80
+ ok: MessagesPage;
81
+ };
82
+ type Result_11 =
83
+ variant {
84
+ err: Error;
85
+ ok: vec Chat;
86
+ };
87
+ type Result_10 =
88
+ variant {
89
+ err: Error;
90
+ ok: vec ChatSummary;
81
91
  };
82
92
  type Result_1 =
83
93
  variant {
84
94
  err: Error;
85
- ok: Chat;
95
+ ok: Project;
86
96
  };
87
97
  type Result =
88
98
  variant {
89
99
  err: Error;
90
- ok: Project;
100
+ ok: Room;
101
+ };
102
+ type RemoveAdminArgs = record {"principal": principal;};
103
+ type RecipientRole =
104
+ variant {
105
+ agent;
106
+ worker;
91
107
  };
92
- type RemoveMemberArgs =
108
+ type Recipient =
93
109
  record {
94
- chatId: ChatId;
110
+ displayName: text;
95
111
  "principal": principal;
112
+ role: RecipientRole;
113
+ };
114
+ type QuotaLimits =
115
+ record {
116
+ chats: nat;
117
+ posts: nat;
96
118
  };
97
- type RemoveAdminArgs = record {"principal": principal;};
98
119
  type PurgeChatArgs = record {chatId: ChatId;};
99
120
  type ProjectId = text;
100
121
  type Project =
101
122
  record {
102
123
  admins: vec principal;
103
- agents: vec principal;
104
- agentsMayInvite: bool;
105
124
  createdAt: int;
106
125
  createdBy: principal;
107
- defaultPolicy: Policy;
108
126
  id: ProjectId;
109
127
  };
110
128
  type PostKind =
@@ -129,7 +147,21 @@ type PollNewMessagesArgs =
129
147
  limit: opt nat;
130
148
  sinceGlobalSeq: nat;
131
149
  };
132
- type Policy = record {agentsReply: bool;};
150
+ type Participant =
151
+ record {
152
+ displayName: text;
153
+ firstPostSeq: opt nat;
154
+ joinedAt: int;
155
+ lastReadSeq: nat;
156
+ "principal": principal;
157
+ role: Role;
158
+ };
159
+ type OpenChatArgs =
160
+ record {
161
+ customerName: opt text;
162
+ projectId: ProjectId;
163
+ roomId: RoomId;
164
+ };
133
165
  type MessagesPage =
134
166
  record {
135
167
  lastSeq: nat;
@@ -146,44 +178,42 @@ type Message =
146
178
  author: principal;
147
179
  chatId: ChatId;
148
180
  createdAt: int;
181
+ customer: principal;
149
182
  globalSeq: nat;
150
183
  kind: MessageKind;
151
184
  projectId: ProjectId;
185
+ roomId: RoomId;
152
186
  seq: nat;
153
187
  "text": text;
154
188
  };
155
- type MemberInput =
156
- record {
157
- "principal": principal;
158
- role: Role;
159
- };
160
- type Member =
161
- record {
162
- joinedAt: int;
163
- lastReadSeq: nat;
164
- "principal": principal;
165
- role: Role;
166
- };
167
189
  type MarkReadArgs =
168
190
  record {
169
191
  chatId: ChatId;
170
192
  seq: nat;
171
193
  };
194
+ type ListRoomsArgs =
195
+ record {
196
+ limit: opt nat;
197
+ projectId: ProjectId;
198
+ };
172
199
  type ListProjectsArgs = record {limit: opt nat;};
173
- type LeaveChatArgs = record {chatId: ChatId;};
174
- type InviteMemberArgs =
200
+ type ListProjectChatsArgs =
175
201
  record {
176
- chatId: ChatId;
177
- "principal": principal;
178
- role: Role;
202
+ limit: opt nat;
203
+ projectId: ProjectId;
204
+ roomId: opt RoomId;
205
+ };
206
+ type GetRoomArgs =
207
+ record {
208
+ projectId: ProjectId;
209
+ roomId: RoomId;
179
210
  };
180
211
  type GetProjectArgs = record {projectId: ProjectId;};
181
212
  type GetMyChatsArgs =
182
213
  record {
183
- includeClosed: bool;
184
214
  limit: opt nat;
185
215
  projectId: ProjectId;
186
- subject: opt text;
216
+ roomId: opt RoomId;
187
217
  };
188
218
  type GetMessagesArgs =
189
219
  record {
@@ -207,69 +237,68 @@ type Error =
207
237
  details: ErrorDetails;
208
238
  logsJson: text;
209
239
  };
240
+ type CreateRoomArgs =
241
+ record {
242
+ id: RoomId;
243
+ name: text;
244
+ projectId: ProjectId;
245
+ recipients: vec Recipient;
246
+ };
210
247
  type CreateProjectArgs =
211
248
  record {
212
249
  admins: vec principal;
213
- agents: vec principal;
214
- agentsMayInvite: bool;
215
- defaultPolicy: Policy;
216
250
  id: ProjectId;
217
251
  };
218
- type CreateChatArgs =
252
+ type ChatSummary =
219
253
  record {
220
- firstMessage: opt text;
221
- members: vec MemberInput;
222
- policy: opt Policy;
254
+ createdAt: int;
255
+ customer: principal;
256
+ id: ChatId;
257
+ lastMessageAt: int;
258
+ messageCount: nat;
259
+ participantCount: nat;
223
260
  projectId: ProjectId;
224
- subject: opt text;
225
- title: opt text;
226
- };
227
- type CloseChatArgs = record {chatId: ChatId;};
228
- type ChatStatus =
229
- variant {
230
- closed;
231
- open;
261
+ roomId: RoomId;
232
262
  };
233
263
  type ChatId = text;
234
264
  type Chat =
235
265
  record {
236
266
  createdAt: int;
237
- createdBy: principal;
267
+ customer: principal;
238
268
  id: ChatId;
239
269
  lastMessageAt: int;
240
270
  lastSeq: nat;
241
- members: vec Member;
242
- policy: Policy;
271
+ participants: vec Participant;
243
272
  projectId: ProjectId;
244
- status: ChatStatus;
245
- subject: opt text;
246
- title: opt text;
273
+ roomId: RoomId;
247
274
  };
248
275
  type AddAdminArgs = record {"principal": principal;};
249
276
  service : {
250
- addAdmin: (args: AddAdminArgs) -> (Result_2);
277
+ addAdmin: (args: AddAdminArgs) -> (Result_3);
251
278
  clearLogs: () -> ();
252
- closeChat: (args: CloseChatArgs) -> (Result_1);
253
- createChat: (args: CreateChatArgs) -> (Result_1);
254
- createProject: (args: CreateProjectArgs) -> (Result);
255
- getAdmins: () -> (Result_9) query;
256
- getChat: (args: GetChatArgs) -> (Result_1) query;
279
+ createProject: (args: CreateProjectArgs) -> (Result_1);
280
+ createRoom: (args: CreateRoomArgs) -> (Result);
281
+ getAdmins: () -> (Result_13) query;
282
+ getChat: (args: GetChatArgs) -> (Result_7) query;
257
283
  getLogs: () -> (text) query;
258
- getMessages: (args: GetMessagesArgs) -> (Result_8) query;
259
- getMyChats: (args: GetMyChatsArgs) -> (Result_7) query;
260
- getProject: (args: GetProjectArgs) -> (Result) query;
261
- inviteMember: (args: InviteMemberArgs) -> (Result_1);
262
- leaveChat: (args: LeaveChatArgs) -> (Result_2);
263
- listProjects: (args: ListProjectsArgs) -> (Result_6) query;
264
- markRead: (args: MarkReadArgs) -> (Result_2);
265
- pollNewMessages: (args: PollNewMessagesArgs) -> (Result_5) query;
266
- post: (args: PostArgs) -> (Result_4);
267
- purgeChat: (args: PurgeChatArgs) -> (Result_2);
268
- registerAsAdmin: () -> (Result_3);
269
- removeAdmin: (args: RemoveAdminArgs) -> (Result_2);
270
- removeMember: (args: RemoveMemberArgs) -> (Result_1);
271
- setLoggingEnabled: (args: SetLoggingEnabledArgs) -> (Result_2);
272
- setPolicy: (args: SetPolicyArgs) -> (Result_1);
273
- updateProject: (args: UpdateProjectArgs) -> (Result);
284
+ getMessages: (args: GetMessagesArgs) -> (Result_12) query;
285
+ getMyChats: (args: GetMyChatsArgs) -> (Result_11) query;
286
+ getProject: (args: GetProjectArgs) -> (Result_1) query;
287
+ getQuotaLimits: () -> (Result_2) query;
288
+ getRoom: (args: GetRoomArgs) -> (Result) query;
289
+ listProjectChats: (args: ListProjectChatsArgs) -> (Result_10) query;
290
+ listProjects: (args: ListProjectsArgs) -> (Result_9) query;
291
+ listRooms: (args: ListRoomsArgs) -> (Result_8) query;
292
+ markRead: (args: MarkReadArgs) -> (Result_3);
293
+ openChat: (args: OpenChatArgs) -> (Result_7);
294
+ pollNewMessages: (args: PollNewMessagesArgs) -> (Result_6) query;
295
+ post: (args: PostArgs) -> (Result_5);
296
+ purgeChat: (args: PurgeChatArgs) -> (Result_3);
297
+ registerAsAdmin: () -> (Result_4);
298
+ removeAdmin: (args: RemoveAdminArgs) -> (Result_3);
299
+ setLoggingEnabled: (args: SetLoggingEnabledArgs) -> (Result_3);
300
+ setQuotaLimits: (args: SetQuotaLimitsArgs) -> (Result_2);
301
+ updateProject: (args: UpdateProjectArgs) -> (Result_1);
302
+ updateRoom: (args: UpdateRoomArgs) -> (Result);
274
303
  whoAmI: () -> (principal) query;
275
304
  }