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