@unboundcx/sdk 4.8.8 → 4.8.10
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/base.js +30 -28
- package/index.js +3 -0
- package/package.json +1 -1
- package/services/chat.js +851 -0
- package/services/inbox.js +49 -2
- package/services/messaging/EmailMailboxesService.js +49 -0
- package/services/taskRouter/CCService.js +4 -4
- package/services/video.js +60 -20
- package/services/voice.js +28 -0
package/base.js
CHANGED
|
@@ -410,37 +410,36 @@ export class BaseSDK {
|
|
|
410
410
|
'application/json';
|
|
411
411
|
|
|
412
412
|
if (!response.ok) {
|
|
413
|
+
// A fetch Response's `.body` is a ReadableStream, not the parsed
|
|
414
|
+
// payload — it must go through json()/text() or the API's
|
|
415
|
+
// `{ message }` envelope is lost and every error surfaces as the
|
|
416
|
+
// generic "API Error". Only NATS-transport responses carry a
|
|
417
|
+
// pre-parsed `.body`.
|
|
413
418
|
let errorBody;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
) {
|
|
422
|
-
|
|
423
|
-
errorBody = await response.json();
|
|
424
|
-
} else if (contentType.includes('text/')) {
|
|
425
|
-
errorBody = await response.text();
|
|
426
|
-
}
|
|
427
|
-
} else {
|
|
428
|
-
if (contentType.includes('application/json')) {
|
|
429
|
-
errorBody = this._getJsonSafely(
|
|
430
|
-
response?.body,
|
|
431
|
-
response?.body || {},
|
|
432
|
-
);
|
|
433
|
-
} else if (contentType.includes('text/')) {
|
|
434
|
-
errorBody = response?.body || '';
|
|
435
|
-
}
|
|
419
|
+
try {
|
|
420
|
+
if (
|
|
421
|
+
typeof response?.json === 'function' ||
|
|
422
|
+
typeof response?.text === 'function'
|
|
423
|
+
) {
|
|
424
|
+
if (contentType.includes('application/json')) {
|
|
425
|
+
errorBody = await response.json();
|
|
426
|
+
} else if (contentType.includes('text/')) {
|
|
427
|
+
errorBody = await response.text();
|
|
436
428
|
}
|
|
437
|
-
|
|
438
|
-
|
|
429
|
+
} else if (response?.body) {
|
|
430
|
+
if (contentType.includes('application/json')) {
|
|
431
|
+
errorBody = this._getJsonSafely(
|
|
432
|
+
response?.body,
|
|
433
|
+
response?.body || {},
|
|
434
|
+
);
|
|
435
|
+
} else {
|
|
436
|
+
errorBody = response.body;
|
|
439
437
|
}
|
|
440
|
-
} catch (parseError) {
|
|
441
|
-
errorBody = `HTTP ${response.status} ${response.statusText}`;
|
|
442
438
|
}
|
|
443
|
-
}
|
|
439
|
+
} catch (parseError) {
|
|
440
|
+
// fall through to the status-line fallback below
|
|
441
|
+
}
|
|
442
|
+
if (!errorBody) {
|
|
444
443
|
errorBody = `HTTP ${response.status} ${response.statusText}`;
|
|
445
444
|
}
|
|
446
445
|
|
|
@@ -455,7 +454,10 @@ export class BaseSDK {
|
|
|
455
454
|
httpError.method = method;
|
|
456
455
|
httpError.endpoint = endpoint;
|
|
457
456
|
httpError.body = errorBody;
|
|
458
|
-
httpError.message =
|
|
457
|
+
httpError.message =
|
|
458
|
+
errorBody?.error ||
|
|
459
|
+
errorBody?.message ||
|
|
460
|
+
(typeof errorBody === 'string' ? errorBody : 'API Error');
|
|
459
461
|
|
|
460
462
|
// Debug logging for successful HTTP requests
|
|
461
463
|
if (this.debugMode) {
|
package/index.js
CHANGED
|
@@ -33,6 +33,7 @@ import { TriggersService } from './services/triggers.js';
|
|
|
33
33
|
import { InboxService } from './services/inbox.js';
|
|
34
34
|
import { SearchService } from './services/search.js';
|
|
35
35
|
import { DirectoryService } from './services/directory.js';
|
|
36
|
+
import { ChatService } from './services/chat.js';
|
|
36
37
|
|
|
37
38
|
class UnboundSDK extends BaseSDK {
|
|
38
39
|
constructor(options = {}) {
|
|
@@ -107,6 +108,7 @@ class UnboundSDK extends BaseSDK {
|
|
|
107
108
|
this.inbox = new InboxService(this);
|
|
108
109
|
this.search = new SearchService(this);
|
|
109
110
|
this.directory = new DirectoryService(this);
|
|
111
|
+
this.chat = new ChatService(this);
|
|
110
112
|
|
|
111
113
|
// Add additional services that might be missing
|
|
112
114
|
this._initializeAdditionalServices();
|
|
@@ -290,4 +292,5 @@ export { PermissionsService } from './services/permissions.js';
|
|
|
290
292
|
export { InboxService } from './services/inbox.js';
|
|
291
293
|
export { SearchService } from './services/search.js';
|
|
292
294
|
export { DirectoryService } from './services/directory.js';
|
|
295
|
+
export { ChatService } from './services/chat.js';
|
|
293
296
|
export { BaseSDK } from './base.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.10",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/services/chat.js
ADDED
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatService — channels, DMs, membership, unreads, DND, messages, search,
|
|
3
|
+
* webhooks, card actions, reports, admin review, admin export, record feeds,
|
|
4
|
+
* channel meet, push devices, and notifyLevel.
|
|
5
|
+
* Backed by /chat/* on app1-api (checkApiAuth). Incoming webhook POST
|
|
6
|
+
* (HMAC) is external and is not an SDK method.
|
|
7
|
+
*/
|
|
8
|
+
export class ChatService {
|
|
9
|
+
constructor(sdk) {
|
|
10
|
+
this.sdk = sdk;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a channel.
|
|
15
|
+
* @param {Object} params
|
|
16
|
+
* @param {string} params.name - Channel name (required)
|
|
17
|
+
* @param {string} [params.topic]
|
|
18
|
+
* @param {'public'|'private'|'dm'|'group_dm'|'record'|'meeting'} [params.kind]
|
|
19
|
+
* @param {Object} [params.settings]
|
|
20
|
+
* @param {string[]} [params.groupIds] - Groups whose members are auto-added
|
|
21
|
+
* @returns {Promise<Object>} Created channel
|
|
22
|
+
*/
|
|
23
|
+
async createChannel({ name, topic, kind, settings, groupIds }) {
|
|
24
|
+
this.sdk.validateParams(
|
|
25
|
+
{ name, topic, kind, settings, groupIds },
|
|
26
|
+
{
|
|
27
|
+
name: { type: 'string', required: true },
|
|
28
|
+
topic: { type: 'string', required: false },
|
|
29
|
+
kind: { type: 'string', required: false },
|
|
30
|
+
settings: { type: 'object', required: false },
|
|
31
|
+
groupIds: { type: 'array', required: false },
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const body = { name };
|
|
36
|
+
if (topic !== undefined) body.topic = topic;
|
|
37
|
+
if (kind !== undefined) body.kind = kind;
|
|
38
|
+
if (settings !== undefined) body.settings = settings;
|
|
39
|
+
if (groupIds !== undefined) body.groupIds = groupIds;
|
|
40
|
+
|
|
41
|
+
return this.sdk._fetch('/chat/channels', 'POST', { body });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* List channels the current user is a member of.
|
|
46
|
+
* @returns {Promise<Object>}
|
|
47
|
+
*/
|
|
48
|
+
async listChannels() {
|
|
49
|
+
return this.sdk._fetch('/chat/channels', 'GET');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Browse joinable (public) channels.
|
|
54
|
+
* @returns {Promise<Object>}
|
|
55
|
+
*/
|
|
56
|
+
async browseChannels() {
|
|
57
|
+
return this.sdk._fetch('/chat/channels/browse', 'GET');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get a channel by id.
|
|
62
|
+
* @param {string} id
|
|
63
|
+
* @returns {Promise<Object>}
|
|
64
|
+
*/
|
|
65
|
+
async getChannel(id) {
|
|
66
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
67
|
+
return this.sdk._fetch(`/chat/channels/${id}`, 'GET');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Update channel name/topic/settings.
|
|
72
|
+
* @param {string} id
|
|
73
|
+
* @param {Object} [params]
|
|
74
|
+
* @param {string} [params.name]
|
|
75
|
+
* @param {string} [params.topic]
|
|
76
|
+
* @param {Object} [params.settings]
|
|
77
|
+
* @returns {Promise<Object>}
|
|
78
|
+
*/
|
|
79
|
+
async updateChannel(id, { name, topic, settings } = {}) {
|
|
80
|
+
this.sdk.validateParams(
|
|
81
|
+
{ id, name, topic, settings },
|
|
82
|
+
{
|
|
83
|
+
id: { type: 'string', required: true },
|
|
84
|
+
name: { type: 'string', required: false },
|
|
85
|
+
topic: { type: 'string', required: false },
|
|
86
|
+
settings: { type: 'object', required: false },
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const body = {};
|
|
91
|
+
if (name !== undefined) body.name = name;
|
|
92
|
+
if (topic !== undefined) body.topic = topic;
|
|
93
|
+
if (settings !== undefined) body.settings = settings;
|
|
94
|
+
|
|
95
|
+
return this.sdk._fetch(`/chat/channels/${id}`, 'PATCH', { body });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Archive a channel (reversible; hard delete is not supported).
|
|
100
|
+
* @param {string} id
|
|
101
|
+
* @returns {Promise<Object>}
|
|
102
|
+
*/
|
|
103
|
+
async archiveChannel(id) {
|
|
104
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
105
|
+
return this.sdk._fetch(`/chat/channels/${id}/archive`, 'POST', {
|
|
106
|
+
body: {},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Unarchive a channel.
|
|
112
|
+
* @param {string} id
|
|
113
|
+
* @returns {Promise<Object>}
|
|
114
|
+
*/
|
|
115
|
+
async unarchiveChannel(id) {
|
|
116
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
117
|
+
return this.sdk._fetch(`/chat/channels/${id}/unarchive`, 'POST', {
|
|
118
|
+
body: {},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Join a public channel.
|
|
124
|
+
* @param {string} id
|
|
125
|
+
* @returns {Promise<Object>}
|
|
126
|
+
*/
|
|
127
|
+
async joinChannel(id) {
|
|
128
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
129
|
+
return this.sdk._fetch(`/chat/channels/${id}/join`, 'POST', { body: {} });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Leave a channel.
|
|
134
|
+
* @param {string} id
|
|
135
|
+
* @returns {Promise<Object>}
|
|
136
|
+
*/
|
|
137
|
+
async leaveChannel(id) {
|
|
138
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
139
|
+
return this.sdk._fetch(`/chat/channels/${id}/leave`, 'POST', { body: {} });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* List members of a channel.
|
|
144
|
+
* @param {string} id
|
|
145
|
+
* @returns {Promise<Object>}
|
|
146
|
+
*/
|
|
147
|
+
async listMembers(id) {
|
|
148
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
149
|
+
return this.sdk._fetch(`/chat/channels/${id}/members`, 'GET');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Add a member to a channel.
|
|
154
|
+
* @param {string} id
|
|
155
|
+
* @param {Object} params
|
|
156
|
+
* @param {string} params.userId
|
|
157
|
+
* @param {'owner'|'moderator'|'member'} [params.role]
|
|
158
|
+
* @returns {Promise<Object>}
|
|
159
|
+
*/
|
|
160
|
+
async addMember(id, { userId, role } = {}) {
|
|
161
|
+
this.sdk.validateParams(
|
|
162
|
+
{ id, userId, role },
|
|
163
|
+
{
|
|
164
|
+
id: { type: 'string', required: true },
|
|
165
|
+
userId: { type: 'string', required: true },
|
|
166
|
+
role: { type: 'string', required: false },
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const body = { userId };
|
|
171
|
+
if (role !== undefined) body.role = role;
|
|
172
|
+
|
|
173
|
+
return this.sdk._fetch(`/chat/channels/${id}/members`, 'POST', { body });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Remove a member from a channel.
|
|
178
|
+
* @param {string} id
|
|
179
|
+
* @param {string} userId
|
|
180
|
+
* @returns {Promise<Object>}
|
|
181
|
+
*/
|
|
182
|
+
async removeMember(id, userId) {
|
|
183
|
+
this.sdk.validateParams(
|
|
184
|
+
{ id, userId },
|
|
185
|
+
{
|
|
186
|
+
id: { type: 'string', required: true },
|
|
187
|
+
userId: { type: 'string', required: true },
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
return this.sdk._fetch(`/chat/channels/${id}/members/${userId}`, 'DELETE');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get group-default membership links for a channel.
|
|
195
|
+
* @param {string} id
|
|
196
|
+
* @returns {Promise<Object>}
|
|
197
|
+
*/
|
|
198
|
+
async getGroupDefaults(id) {
|
|
199
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
200
|
+
return this.sdk._fetch(`/chat/channels/${id}/group-defaults`, 'GET');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Replace group-default membership links for a channel.
|
|
205
|
+
* @param {string} id
|
|
206
|
+
* @param {Object} params
|
|
207
|
+
* @param {string[]} params.groupIds
|
|
208
|
+
* @returns {Promise<Object>}
|
|
209
|
+
*/
|
|
210
|
+
async setGroupDefaults(id, { groupIds } = {}) {
|
|
211
|
+
this.sdk.validateParams(
|
|
212
|
+
{ id, groupIds },
|
|
213
|
+
{
|
|
214
|
+
id: { type: 'string', required: true },
|
|
215
|
+
groupIds: { type: 'array', required: true },
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
return this.sdk._fetch(`/chat/channels/${id}/group-defaults`, 'PUT', {
|
|
219
|
+
body: { groupIds },
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Find-or-create a 1:1 or group DM.
|
|
225
|
+
* @param {Object} params
|
|
226
|
+
* @param {string[]} params.userIds
|
|
227
|
+
* @returns {Promise<Object>}
|
|
228
|
+
*/
|
|
229
|
+
async openDm({ userIds }) {
|
|
230
|
+
this.sdk.validateParams(
|
|
231
|
+
{ userIds },
|
|
232
|
+
{ userIds: { type: 'array', required: true } },
|
|
233
|
+
);
|
|
234
|
+
return this.sdk._fetch('/chat/dms', 'POST', { body: { userIds } });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Sidebar unread snapshot (channels + previews + counters).
|
|
239
|
+
* @returns {Promise<Object>}
|
|
240
|
+
*/
|
|
241
|
+
async getUnreads() {
|
|
242
|
+
return this.sdk._fetch('/chat/unreads', 'GET');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get the caller's Do Not Disturb state.
|
|
247
|
+
* @returns {Promise<Object>}
|
|
248
|
+
*/
|
|
249
|
+
async getDnd() {
|
|
250
|
+
return this.sdk._fetch('/chat/dnd', 'GET');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Set the caller's Do Not Disturb state.
|
|
255
|
+
* @param {Object} params
|
|
256
|
+
* @param {boolean} params.enabled
|
|
257
|
+
* @returns {Promise<Object>}
|
|
258
|
+
*/
|
|
259
|
+
async setDnd({ enabled } = {}) {
|
|
260
|
+
this.sdk.validateParams(
|
|
261
|
+
{ enabled },
|
|
262
|
+
{ enabled: { type: 'boolean', required: true } },
|
|
263
|
+
);
|
|
264
|
+
return this.sdk._fetch('/chat/dnd', 'PATCH', { body: { enabled } });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Advance the read watermark and recompute unread counters.
|
|
269
|
+
* @param {string} channelId
|
|
270
|
+
* @param {string} messageId
|
|
271
|
+
* @returns {Promise<Object>}
|
|
272
|
+
*/
|
|
273
|
+
async markRead(channelId, messageId) {
|
|
274
|
+
this.sdk.validateParams(
|
|
275
|
+
{ channelId, messageId },
|
|
276
|
+
{
|
|
277
|
+
channelId: { type: 'string', required: true },
|
|
278
|
+
messageId: { type: 'string', required: true },
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/read`, 'POST', {
|
|
282
|
+
body: { messageId },
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Set the watermark to the message before `messageId` (mark as unread).
|
|
288
|
+
* @param {string} channelId
|
|
289
|
+
* @param {string} messageId
|
|
290
|
+
* @returns {Promise<Object>}
|
|
291
|
+
*/
|
|
292
|
+
async markUnread(channelId, messageId) {
|
|
293
|
+
this.sdk.validateParams(
|
|
294
|
+
{ channelId, messageId },
|
|
295
|
+
{
|
|
296
|
+
channelId: { type: 'string', required: true },
|
|
297
|
+
messageId: { type: 'string', required: true },
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/unread`, 'POST', {
|
|
301
|
+
body: { messageId },
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Channels linked to a group via defaults (remove-from-group prompt).
|
|
307
|
+
* @param {Object} params
|
|
308
|
+
* @param {string} params.groupId
|
|
309
|
+
* @param {string} params.userId
|
|
310
|
+
* @returns {Promise<Object>}
|
|
311
|
+
*/
|
|
312
|
+
async getLinkedChannels({ groupId, userId }) {
|
|
313
|
+
this.sdk.validateParams(
|
|
314
|
+
{ groupId, userId },
|
|
315
|
+
{
|
|
316
|
+
groupId: { type: 'string', required: true },
|
|
317
|
+
userId: { type: 'string', required: true },
|
|
318
|
+
},
|
|
319
|
+
);
|
|
320
|
+
return this.sdk._fetch(`/chat/groups/${groupId}/linked-channels`, 'GET', {
|
|
321
|
+
query: { userId },
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* List messages in a channel (cursor pagination).
|
|
327
|
+
* @param {string} channelId
|
|
328
|
+
* @param {Object} [params]
|
|
329
|
+
* @param {string} [params.before]
|
|
330
|
+
* @param {string} [params.after]
|
|
331
|
+
* @param {number} [params.limit]
|
|
332
|
+
* @returns {Promise<Object>}
|
|
333
|
+
*/
|
|
334
|
+
async listMessages(channelId, { before, after, limit } = {}) {
|
|
335
|
+
this.sdk.validateParams(
|
|
336
|
+
{ channelId, before, after, limit },
|
|
337
|
+
{
|
|
338
|
+
channelId: { type: 'string', required: true },
|
|
339
|
+
before: { type: 'string', required: false },
|
|
340
|
+
after: { type: 'string', required: false },
|
|
341
|
+
limit: { type: 'number', required: false },
|
|
342
|
+
},
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const query = {};
|
|
346
|
+
if (before !== undefined) query.before = before;
|
|
347
|
+
if (after !== undefined) query.after = after;
|
|
348
|
+
if (limit !== undefined) query.limit = limit;
|
|
349
|
+
|
|
350
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/messages`, 'GET', {
|
|
351
|
+
query,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Send a message to a channel.
|
|
357
|
+
* @param {string} channelId
|
|
358
|
+
* @param {Object} params
|
|
359
|
+
* @param {Object} params.message - ProseMirror JSON (required)
|
|
360
|
+
* @param {string} [params.threadRootId]
|
|
361
|
+
* @param {boolean} [params.alsoSendToChannel]
|
|
362
|
+
* @param {string[]} [params.storageIds]
|
|
363
|
+
* @returns {Promise<Object>} Created message
|
|
364
|
+
*/
|
|
365
|
+
async sendMessage(
|
|
366
|
+
channelId,
|
|
367
|
+
{ message, threadRootId, alsoSendToChannel, storageIds } = {},
|
|
368
|
+
) {
|
|
369
|
+
this.sdk.validateParams(
|
|
370
|
+
{ channelId, message, threadRootId, alsoSendToChannel, storageIds },
|
|
371
|
+
{
|
|
372
|
+
channelId: { type: 'string', required: true },
|
|
373
|
+
message: { type: 'object', required: true },
|
|
374
|
+
threadRootId: { type: 'string', required: false },
|
|
375
|
+
alsoSendToChannel: { type: 'boolean', required: false },
|
|
376
|
+
storageIds: { type: 'array', required: false },
|
|
377
|
+
},
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
const body = { message };
|
|
381
|
+
if (threadRootId !== undefined) body.threadRootId = threadRootId;
|
|
382
|
+
if (alsoSendToChannel !== undefined) {
|
|
383
|
+
body.alsoSendToChannel = alsoSendToChannel;
|
|
384
|
+
}
|
|
385
|
+
if (storageIds !== undefined) body.storageIds = storageIds;
|
|
386
|
+
|
|
387
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/messages`, 'POST', {
|
|
388
|
+
body,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Edit a message body (ProseMirror JSON).
|
|
394
|
+
* @param {string} id
|
|
395
|
+
* @param {Object} params
|
|
396
|
+
* @param {Object} params.message - ProseMirror JSON (required)
|
|
397
|
+
* @returns {Promise<Object>}
|
|
398
|
+
*/
|
|
399
|
+
async editMessage(id, { message } = {}) {
|
|
400
|
+
this.sdk.validateParams(
|
|
401
|
+
{ id, message },
|
|
402
|
+
{
|
|
403
|
+
id: { type: 'string', required: true },
|
|
404
|
+
message: { type: 'object', required: true },
|
|
405
|
+
},
|
|
406
|
+
);
|
|
407
|
+
return this.sdk._fetch(`/chat/messages/${id}`, 'PATCH', {
|
|
408
|
+
body: { message },
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Delete a message (tombstone).
|
|
414
|
+
* @param {string} id
|
|
415
|
+
* @returns {Promise<Object>}
|
|
416
|
+
*/
|
|
417
|
+
async deleteMessage(id) {
|
|
418
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
419
|
+
return this.sdk._fetch(`/chat/messages/${id}`, 'DELETE');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Add an emoji reaction to a message.
|
|
424
|
+
* @param {string} id
|
|
425
|
+
* @param {Object} params
|
|
426
|
+
* @param {string} params.emoji
|
|
427
|
+
* @returns {Promise<Object>}
|
|
428
|
+
*/
|
|
429
|
+
async addReaction(id, { emoji } = {}) {
|
|
430
|
+
this.sdk.validateParams(
|
|
431
|
+
{ id, emoji },
|
|
432
|
+
{
|
|
433
|
+
id: { type: 'string', required: true },
|
|
434
|
+
emoji: { type: 'string', required: true },
|
|
435
|
+
},
|
|
436
|
+
);
|
|
437
|
+
return this.sdk._fetch(`/chat/messages/${id}/reactions`, 'POST', {
|
|
438
|
+
body: { emoji },
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Remove an emoji reaction from a message.
|
|
444
|
+
* @param {string} id
|
|
445
|
+
* @param {Object} params
|
|
446
|
+
* @param {string} params.emoji
|
|
447
|
+
* @returns {Promise<Object>}
|
|
448
|
+
*/
|
|
449
|
+
async removeReaction(id, { emoji } = {}) {
|
|
450
|
+
this.sdk.validateParams(
|
|
451
|
+
{ id, emoji },
|
|
452
|
+
{
|
|
453
|
+
id: { type: 'string', required: true },
|
|
454
|
+
emoji: { type: 'string', required: true },
|
|
455
|
+
},
|
|
456
|
+
);
|
|
457
|
+
return this.sdk._fetch(`/chat/messages/${id}/reactions`, 'DELETE', {
|
|
458
|
+
body: { emoji },
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Get a thread (root + replies) for a channel message.
|
|
464
|
+
* @param {string} channelId
|
|
465
|
+
* @param {string} rootId
|
|
466
|
+
* @returns {Promise<Object>}
|
|
467
|
+
*/
|
|
468
|
+
async getThread(channelId, rootId) {
|
|
469
|
+
this.sdk.validateParams(
|
|
470
|
+
{ channelId, rootId },
|
|
471
|
+
{
|
|
472
|
+
channelId: { type: 'string', required: true },
|
|
473
|
+
rootId: { type: 'string', required: true },
|
|
474
|
+
},
|
|
475
|
+
);
|
|
476
|
+
return this.sdk._fetch(
|
|
477
|
+
`/chat/channels/${channelId}/messages/${rootId}/thread`,
|
|
478
|
+
'GET',
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Search messages the current user can read.
|
|
484
|
+
* @param {Object} params
|
|
485
|
+
* @param {string} params.q - Search term (required)
|
|
486
|
+
* @param {string} [params.channelId]
|
|
487
|
+
* @param {string} [params.fromUserId]
|
|
488
|
+
* @param {string} [params.before]
|
|
489
|
+
* @param {string} [params.after]
|
|
490
|
+
* @param {'public'|'private'|'dm'|'group_dm'|'record'|'meeting'} [params.kind]
|
|
491
|
+
* @param {string} [params.nextId]
|
|
492
|
+
* @param {number} [params.limit]
|
|
493
|
+
* @returns {Promise<Object>}
|
|
494
|
+
*/
|
|
495
|
+
async search({
|
|
496
|
+
q,
|
|
497
|
+
channelId,
|
|
498
|
+
fromUserId,
|
|
499
|
+
before,
|
|
500
|
+
after,
|
|
501
|
+
kind,
|
|
502
|
+
nextId,
|
|
503
|
+
limit,
|
|
504
|
+
} = {}) {
|
|
505
|
+
this.sdk.validateParams(
|
|
506
|
+
{ q, channelId, fromUserId, before, after, kind, nextId, limit },
|
|
507
|
+
{
|
|
508
|
+
q: { type: 'string', required: true },
|
|
509
|
+
channelId: { type: 'string', required: false },
|
|
510
|
+
fromUserId: { type: 'string', required: false },
|
|
511
|
+
before: { type: 'string', required: false },
|
|
512
|
+
after: { type: 'string', required: false },
|
|
513
|
+
kind: { type: 'string', required: false },
|
|
514
|
+
nextId: { type: 'string', required: false },
|
|
515
|
+
limit: { type: 'number', required: false },
|
|
516
|
+
},
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const query = { q };
|
|
520
|
+
if (channelId !== undefined) query.channelId = channelId;
|
|
521
|
+
if (fromUserId !== undefined) query.fromUserId = fromUserId;
|
|
522
|
+
if (before !== undefined) query.before = before;
|
|
523
|
+
if (after !== undefined) query.after = after;
|
|
524
|
+
if (kind !== undefined) query.kind = kind;
|
|
525
|
+
if (nextId !== undefined) query.nextId = nextId;
|
|
526
|
+
if (limit !== undefined) query.limit = limit;
|
|
527
|
+
|
|
528
|
+
return this.sdk._fetch('/chat/search', 'GET', { query });
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Create a channel incoming webhook (signing secret returned once).
|
|
533
|
+
* Button callback URLs are registered here — never taken from message payloads.
|
|
534
|
+
* @param {string} channelId
|
|
535
|
+
* @param {Object} params
|
|
536
|
+
* @param {string} params.name - Display name (required)
|
|
537
|
+
* @param {string} [params.avatar]
|
|
538
|
+
* @param {string} [params.callbackUrl] - Admin-registered button callback URL
|
|
539
|
+
* @returns {Promise<Object>} Created webhook (includes signingSecret once)
|
|
540
|
+
*/
|
|
541
|
+
async createWebhook(channelId, { name, avatar, callbackUrl } = {}) {
|
|
542
|
+
this.sdk.validateParams(
|
|
543
|
+
{ channelId, name, avatar, callbackUrl },
|
|
544
|
+
{
|
|
545
|
+
channelId: { type: 'string', required: true },
|
|
546
|
+
name: { type: 'string', required: true },
|
|
547
|
+
avatar: { type: 'string', required: false },
|
|
548
|
+
callbackUrl: { type: 'string', required: false },
|
|
549
|
+
},
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const body = { name };
|
|
553
|
+
if (avatar !== undefined) body.avatar = avatar;
|
|
554
|
+
if (callbackUrl !== undefined) body.callbackUrl = callbackUrl;
|
|
555
|
+
|
|
556
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/webhooks`, 'POST', {
|
|
557
|
+
body,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* List webhooks for a channel.
|
|
563
|
+
* @param {string} channelId
|
|
564
|
+
* @returns {Promise<Object>}
|
|
565
|
+
*/
|
|
566
|
+
async listWebhooks(channelId) {
|
|
567
|
+
this.sdk.validateParams(
|
|
568
|
+
{ channelId },
|
|
569
|
+
{ channelId: { type: 'string', required: true } },
|
|
570
|
+
);
|
|
571
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/webhooks`, 'GET');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Revoke a channel webhook.
|
|
576
|
+
* @param {string} channelId
|
|
577
|
+
* @param {string} webhookId
|
|
578
|
+
* @returns {Promise<Object>}
|
|
579
|
+
*/
|
|
580
|
+
async revokeWebhook(channelId, webhookId) {
|
|
581
|
+
this.sdk.validateParams(
|
|
582
|
+
{ channelId, webhookId },
|
|
583
|
+
{
|
|
584
|
+
channelId: { type: 'string', required: true },
|
|
585
|
+
webhookId: { type: 'string', required: true },
|
|
586
|
+
},
|
|
587
|
+
);
|
|
588
|
+
return this.sdk._fetch(
|
|
589
|
+
`/chat/channels/${channelId}/webhooks/${webhookId}`,
|
|
590
|
+
'DELETE',
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Click a card action button on a message. Acting principal is the caller.
|
|
596
|
+
* @param {string} messageId
|
|
597
|
+
* @param {Object} params
|
|
598
|
+
* @param {string} params.actionId
|
|
599
|
+
* @param {string} [params.value]
|
|
600
|
+
* @returns {Promise<Object>}
|
|
601
|
+
*/
|
|
602
|
+
async clickAction(messageId, { actionId, value } = {}) {
|
|
603
|
+
this.sdk.validateParams(
|
|
604
|
+
{ messageId, actionId, value },
|
|
605
|
+
{
|
|
606
|
+
messageId: { type: 'string', required: true },
|
|
607
|
+
actionId: { type: 'string', required: true },
|
|
608
|
+
value: { type: 'string', required: false },
|
|
609
|
+
},
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
const body = { actionId };
|
|
613
|
+
if (value !== undefined) body.value = value;
|
|
614
|
+
|
|
615
|
+
return this.sdk._fetch(`/chat/messages/${messageId}/actions`, 'POST', {
|
|
616
|
+
body,
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Report a message.
|
|
622
|
+
* @param {string} id
|
|
623
|
+
* @param {Object} params
|
|
624
|
+
* @param {string} params.reason
|
|
625
|
+
* @returns {Promise<Object>}
|
|
626
|
+
*/
|
|
627
|
+
async reportMessage(id, { reason } = {}) {
|
|
628
|
+
this.sdk.validateParams(
|
|
629
|
+
{ id, reason },
|
|
630
|
+
{
|
|
631
|
+
id: { type: 'string', required: true },
|
|
632
|
+
reason: { type: 'string', required: true },
|
|
633
|
+
},
|
|
634
|
+
);
|
|
635
|
+
return this.sdk._fetch(`/chat/messages/${id}/report`, 'POST', {
|
|
636
|
+
body: { reason },
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Admin: list all channels (optional search/kind filter).
|
|
642
|
+
* @param {Object} [params]
|
|
643
|
+
* @param {string} [params.q]
|
|
644
|
+
* @param {'public'|'private'|'dm'|'group_dm'|'record'|'meeting'} [params.kind]
|
|
645
|
+
* @returns {Promise<Object>}
|
|
646
|
+
*/
|
|
647
|
+
async adminListChannels({ q, kind } = {}) {
|
|
648
|
+
this.sdk.validateParams(
|
|
649
|
+
{ q, kind },
|
|
650
|
+
{
|
|
651
|
+
q: { type: 'string', required: false },
|
|
652
|
+
kind: { type: 'string', required: false },
|
|
653
|
+
},
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
const query = {};
|
|
657
|
+
if (q !== undefined) query.q = q;
|
|
658
|
+
if (kind !== undefined) query.kind = kind;
|
|
659
|
+
|
|
660
|
+
return this.sdk._fetch('/chat/admin/channels', 'GET', { query });
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Admin: get a channel by id (no membership required).
|
|
665
|
+
* @param {string} id
|
|
666
|
+
* @returns {Promise<Object>}
|
|
667
|
+
*/
|
|
668
|
+
async adminGetChannel(id) {
|
|
669
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
670
|
+
return this.sdk._fetch(`/chat/admin/channels/${id}`, 'GET');
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Admin: export a channel (messages + members).
|
|
675
|
+
* @param {string} id
|
|
676
|
+
* @returns {Promise<Object>}
|
|
677
|
+
*/
|
|
678
|
+
async adminExportChannel(id) {
|
|
679
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
680
|
+
return this.sdk._fetch(`/chat/admin/channels/${id}/export`, 'GET');
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Admin: list message reports.
|
|
685
|
+
* @param {Object} [params]
|
|
686
|
+
* @param {string} [params.status]
|
|
687
|
+
* @returns {Promise<Object>}
|
|
688
|
+
*/
|
|
689
|
+
async adminListReports({ status } = {}) {
|
|
690
|
+
this.sdk.validateParams(
|
|
691
|
+
{ status },
|
|
692
|
+
{ status: { type: 'string', required: false } },
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
const query = {};
|
|
696
|
+
if (status !== undefined) query.status = status;
|
|
697
|
+
|
|
698
|
+
return this.sdk._fetch('/chat/admin/reports', 'GET', { query });
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Admin: review a message report (set status).
|
|
703
|
+
* @param {string} id
|
|
704
|
+
* @param {Object} params
|
|
705
|
+
* @param {string} params.status
|
|
706
|
+
* @returns {Promise<Object>}
|
|
707
|
+
*/
|
|
708
|
+
async adminReviewReport(id, { status } = {}) {
|
|
709
|
+
this.sdk.validateParams(
|
|
710
|
+
{ id, status },
|
|
711
|
+
{
|
|
712
|
+
id: { type: 'string', required: true },
|
|
713
|
+
status: { type: 'string', required: true },
|
|
714
|
+
},
|
|
715
|
+
);
|
|
716
|
+
return this.sdk._fetch(`/chat/admin/reports/${id}`, 'POST', {
|
|
717
|
+
body: { status },
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Admin: delete a message (moderation).
|
|
723
|
+
* @param {string} id
|
|
724
|
+
* @returns {Promise<Object>}
|
|
725
|
+
*/
|
|
726
|
+
async adminDeleteMessage(id) {
|
|
727
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
728
|
+
return this.sdk._fetch(`/chat/admin/messages/${id}`, 'DELETE');
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Admin: audit log of review actions.
|
|
733
|
+
* @returns {Promise<Object>}
|
|
734
|
+
*/
|
|
735
|
+
async adminAudit() {
|
|
736
|
+
return this.sdk._fetch('/chat/admin/audit', 'GET');
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Get (find-or-create) the record-feed channel for a related record.
|
|
741
|
+
* @param {string} relatedId
|
|
742
|
+
* @param {Object} params
|
|
743
|
+
* @param {string} params.recordTypeId
|
|
744
|
+
* @returns {Promise<Object>} Record-kind channel
|
|
745
|
+
*/
|
|
746
|
+
async getRecordChannel(relatedId, { recordTypeId } = {}) {
|
|
747
|
+
this.sdk.validateParams(
|
|
748
|
+
{ relatedId, recordTypeId },
|
|
749
|
+
{
|
|
750
|
+
relatedId: { type: 'string', required: true },
|
|
751
|
+
recordTypeId: { type: 'string', required: true },
|
|
752
|
+
},
|
|
753
|
+
);
|
|
754
|
+
return this.sdk._fetch(`/chat/records/${relatedId}`, 'GET', {
|
|
755
|
+
query: { recordTypeId },
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Post a message to a record-feed channel (find-or-create).
|
|
761
|
+
* @param {string} relatedId
|
|
762
|
+
* @param {Object} params
|
|
763
|
+
* @param {Object} params.message - ProseMirror JSON (required)
|
|
764
|
+
* @param {string} params.recordTypeId
|
|
765
|
+
* @returns {Promise<Object>} Created message
|
|
766
|
+
*/
|
|
767
|
+
async postToRecord(relatedId, { message, recordTypeId } = {}) {
|
|
768
|
+
this.sdk.validateParams(
|
|
769
|
+
{ relatedId, message, recordTypeId },
|
|
770
|
+
{
|
|
771
|
+
relatedId: { type: 'string', required: true },
|
|
772
|
+
message: { type: 'object', required: true },
|
|
773
|
+
recordTypeId: { type: 'string', required: true },
|
|
774
|
+
},
|
|
775
|
+
);
|
|
776
|
+
return this.sdk._fetch(`/chat/records/${relatedId}/messages`, 'POST', {
|
|
777
|
+
body: { message, recordTypeId },
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Get the Meet/Call room for a channel.
|
|
783
|
+
* @param {string} channelId
|
|
784
|
+
* @returns {Promise<Object>}
|
|
785
|
+
*/
|
|
786
|
+
async getChannelMeet(channelId) {
|
|
787
|
+
this.sdk.validateParams(
|
|
788
|
+
{ channelId },
|
|
789
|
+
{ channelId: { type: 'string', required: true } },
|
|
790
|
+
);
|
|
791
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/meet`, 'GET');
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Get the VAPID public key for Web Push subscription.
|
|
796
|
+
* @returns {Promise<Object>}
|
|
797
|
+
*/
|
|
798
|
+
async getVapidPublicKey() {
|
|
799
|
+
return this.sdk._fetch('/chat/push/vapidPublicKey', 'GET');
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Register a push device (web push subscription or native FCM/APNs token).
|
|
804
|
+
* @param {Object} params
|
|
805
|
+
* @param {'webpush'|'fcm'|'apns'} params.kind
|
|
806
|
+
* @param {Object} params.subscription - Push subscription / token JSON
|
|
807
|
+
* @returns {Promise<Object>}
|
|
808
|
+
*/
|
|
809
|
+
async registerPushDevice({ kind, subscription } = {}) {
|
|
810
|
+
this.sdk.validateParams(
|
|
811
|
+
{ kind, subscription },
|
|
812
|
+
{
|
|
813
|
+
kind: { type: 'string', required: true },
|
|
814
|
+
subscription: { type: 'object', required: true },
|
|
815
|
+
},
|
|
816
|
+
);
|
|
817
|
+
return this.sdk._fetch('/chat/push/devices', 'POST', {
|
|
818
|
+
body: { kind, subscription },
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Unregister a push device.
|
|
824
|
+
* @param {string} id
|
|
825
|
+
* @returns {Promise<Object>}
|
|
826
|
+
*/
|
|
827
|
+
async unregisterPushDevice(id) {
|
|
828
|
+
this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
|
|
829
|
+
return this.sdk._fetch(`/chat/push/devices/${id}`, 'DELETE');
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Set the caller's notifyLevel on a channel (all | mentions | mute).
|
|
834
|
+
* @param {string} channelId
|
|
835
|
+
* @param {Object} params
|
|
836
|
+
* @param {'all'|'mentions'|'mute'} params.notifyLevel
|
|
837
|
+
* @returns {Promise<Object>}
|
|
838
|
+
*/
|
|
839
|
+
async setNotifyLevel(channelId, { notifyLevel } = {}) {
|
|
840
|
+
this.sdk.validateParams(
|
|
841
|
+
{ channelId, notifyLevel },
|
|
842
|
+
{
|
|
843
|
+
channelId: { type: 'string', required: true },
|
|
844
|
+
notifyLevel: { type: 'string', required: true },
|
|
845
|
+
},
|
|
846
|
+
);
|
|
847
|
+
return this.sdk._fetch(`/chat/channels/${channelId}/notify`, 'PATCH', {
|
|
848
|
+
body: { notifyLevel },
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
}
|
package/services/inbox.js
CHANGED
|
@@ -15,15 +15,53 @@ export class InboxService {
|
|
|
15
15
|
* @param {string} [params.before] - UTC cursor 'YYYY-MM-DD HH:mm:ss';
|
|
16
16
|
* only items strictly older than this are returned.
|
|
17
17
|
* @param {boolean} [params.unreadOnly] - When true, only unread items.
|
|
18
|
+
* @param {string} [params.startDate] - Inclusive range start `YYYY-MM-DD`.
|
|
19
|
+
* @param {string} [params.endDate] - Inclusive range end `YYYY-MM-DD`.
|
|
20
|
+
* @param {string} [params.q] - Search numbers, names, previews.
|
|
21
|
+
* @param {string} [params.direction] - `inbound` or `outbound`.
|
|
22
|
+
* @param {boolean} [params.missed] - Missed inbound calls only.
|
|
23
|
+
* @param {boolean} [params.hasRecording] - Calls/meetings with a recording.
|
|
24
|
+
* @param {boolean} [params.hasTranscription] - Calls/meetings/voicemail
|
|
25
|
+
* with a transcript.
|
|
18
26
|
* @returns {Promise<{items: Object[], nextCursor: string|null}>}
|
|
19
27
|
*/
|
|
20
|
-
async list({
|
|
28
|
+
async list({
|
|
29
|
+
types,
|
|
30
|
+
limit,
|
|
31
|
+
before,
|
|
32
|
+
unreadOnly,
|
|
33
|
+
startDate,
|
|
34
|
+
endDate,
|
|
35
|
+
q,
|
|
36
|
+
direction,
|
|
37
|
+
missed,
|
|
38
|
+
hasRecording,
|
|
39
|
+
hasTranscription,
|
|
40
|
+
} = {}) {
|
|
21
41
|
this.sdk.validateParams(
|
|
22
|
-
{
|
|
42
|
+
{
|
|
43
|
+
limit,
|
|
44
|
+
before,
|
|
45
|
+
unreadOnly,
|
|
46
|
+
startDate,
|
|
47
|
+
endDate,
|
|
48
|
+
q,
|
|
49
|
+
direction,
|
|
50
|
+
missed,
|
|
51
|
+
hasRecording,
|
|
52
|
+
hasTranscription,
|
|
53
|
+
},
|
|
23
54
|
{
|
|
24
55
|
limit: { type: 'number', required: false },
|
|
25
56
|
before: { type: 'string', required: false },
|
|
26
57
|
unreadOnly: { type: 'boolean', required: false },
|
|
58
|
+
startDate: { type: 'string', required: false },
|
|
59
|
+
endDate: { type: 'string', required: false },
|
|
60
|
+
q: { type: 'string', required: false },
|
|
61
|
+
direction: { type: 'string', required: false },
|
|
62
|
+
missed: { type: 'boolean', required: false },
|
|
63
|
+
hasRecording: { type: 'boolean', required: false },
|
|
64
|
+
hasTranscription: { type: 'boolean', required: false },
|
|
27
65
|
},
|
|
28
66
|
);
|
|
29
67
|
|
|
@@ -42,6 +80,15 @@ export class InboxService {
|
|
|
42
80
|
if (limit !== undefined) query.limit = limit;
|
|
43
81
|
if (before !== undefined) query.before = before;
|
|
44
82
|
if (unreadOnly !== undefined) query.unreadOnly = unreadOnly;
|
|
83
|
+
if (startDate !== undefined) query.startDate = startDate;
|
|
84
|
+
if (endDate !== undefined) query.endDate = endDate;
|
|
85
|
+
if (q !== undefined) query.q = q;
|
|
86
|
+
if (direction !== undefined) query.direction = direction;
|
|
87
|
+
if (missed !== undefined) query.missed = missed;
|
|
88
|
+
if (hasRecording !== undefined) query.hasRecording = hasRecording;
|
|
89
|
+
if (hasTranscription !== undefined) {
|
|
90
|
+
query.hasTranscription = hasTranscription;
|
|
91
|
+
}
|
|
45
92
|
|
|
46
93
|
const params = { query };
|
|
47
94
|
|
|
@@ -455,4 +455,53 @@ export class EmailMailboxesService {
|
|
|
455
455
|
);
|
|
456
456
|
return result;
|
|
457
457
|
}
|
|
458
|
+
|
|
459
|
+
async createFolder(mailboxId, { name, parent } = {}) {
|
|
460
|
+
this.sdk.validateParams(
|
|
461
|
+
{ mailboxId, name, parent },
|
|
462
|
+
{
|
|
463
|
+
mailboxId: { type: 'string', required: true },
|
|
464
|
+
name: { type: 'string', required: true },
|
|
465
|
+
parent: { type: 'string', required: false },
|
|
466
|
+
},
|
|
467
|
+
);
|
|
468
|
+
const body = { name };
|
|
469
|
+
if (parent) body.parent = parent;
|
|
470
|
+
return this.sdk._fetch(
|
|
471
|
+
`/messaging/email/mailbox/${mailboxId}/folders`,
|
|
472
|
+
'POST',
|
|
473
|
+
{ body },
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async renameFolder(mailboxId, { from, to } = {}) {
|
|
478
|
+
this.sdk.validateParams(
|
|
479
|
+
{ mailboxId, from, to },
|
|
480
|
+
{
|
|
481
|
+
mailboxId: { type: 'string', required: true },
|
|
482
|
+
from: { type: 'string', required: true },
|
|
483
|
+
to: { type: 'string', required: true },
|
|
484
|
+
},
|
|
485
|
+
);
|
|
486
|
+
return this.sdk._fetch(
|
|
487
|
+
`/messaging/email/mailbox/${mailboxId}/folders`,
|
|
488
|
+
'PUT',
|
|
489
|
+
{ body: { from, to } },
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
async deleteFolder(mailboxId, { name } = {}) {
|
|
494
|
+
this.sdk.validateParams(
|
|
495
|
+
{ mailboxId, name },
|
|
496
|
+
{
|
|
497
|
+
mailboxId: { type: 'string', required: true },
|
|
498
|
+
name: { type: 'string', required: true },
|
|
499
|
+
},
|
|
500
|
+
);
|
|
501
|
+
return this.sdk._fetch(
|
|
502
|
+
`/messaging/email/mailbox/${mailboxId}/folders`,
|
|
503
|
+
'DELETE',
|
|
504
|
+
{ query: { name }, body: { name } },
|
|
505
|
+
);
|
|
506
|
+
}
|
|
458
507
|
}
|
|
@@ -11,7 +11,7 @@ export class CCService {
|
|
|
11
11
|
* @returns {Promise<Object>} result
|
|
12
12
|
* @returns {boolean} result.isManager - Whether the caller has queue-manager scope
|
|
13
13
|
* @returns {string|null} result.workerId - The caller's own worker id, if any
|
|
14
|
-
* @returns {Array<Object>} result.queues - Accessible queues [{id, name, slaThreshold}]
|
|
14
|
+
* @returns {Array<Object>} result.queues - Accessible queues [{id, name, slaThreshold, slaTargetPct, timezone}]
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
17
|
* const scope = await sdk.taskRouter.cc.getScope();
|
|
@@ -30,7 +30,7 @@ export class CCService {
|
|
|
30
30
|
* @param {string[]} [options.queueIds] - Queue ids to scope to (must be a subset of the caller's accessible queues). Omit/empty for full scope.
|
|
31
31
|
* @returns {Promise<Object>} result
|
|
32
32
|
* @returns {Object} result.kpis - Aggregate KPIs (inQueueNow, longestWaitSec, myHandledToday, myAvgHandleSecToday, slaTodayPct, slaTargetPct)
|
|
33
|
-
* @returns {Array<Object>} result.queues - Per-queue summaries (id, name, waiting, longestWaitSec, agentsAvailable, agentsTotal, slaPct, health)
|
|
33
|
+
* @returns {Array<Object>} result.queues - Per-queue summaries (id, name, waiting, longestWaitSec, agentsAvailable, agentsTotal, slaPct, slaThreshold, slaTargetPct, timezone, health)
|
|
34
34
|
* @returns {Array<Object>} result.team - Team roster with active tasks
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
@@ -150,7 +150,7 @@ export class CCService {
|
|
|
150
150
|
*
|
|
151
151
|
* @param {Object} options - Parameters
|
|
152
152
|
* @param {string} options.queueId - Queue id to update
|
|
153
|
-
* @param {Object} options.weights - `{sentiment,
|
|
153
|
+
* @param {Object} options.weights - `{sentiment, aht, volume, acceptance}` ints summing to 100
|
|
154
154
|
* @returns {Promise<Object>} result
|
|
155
155
|
* @returns {string} result.queueId
|
|
156
156
|
* @returns {Object} result.rankingWeights - The stored weights
|
|
@@ -158,7 +158,7 @@ export class CCService {
|
|
|
158
158
|
* @example
|
|
159
159
|
* await sdk.taskRouter.cc.setQueueRankingWeights({
|
|
160
160
|
* queueId: 'q1',
|
|
161
|
-
* weights: { sentiment:
|
|
161
|
+
* weights: { sentiment: 40, aht: 30, volume: 5, acceptance: 25 },
|
|
162
162
|
* });
|
|
163
163
|
*/
|
|
164
164
|
async setQueueRankingWeights(options = {}) {
|
package/services/video.js
CHANGED
|
@@ -1065,7 +1065,10 @@ export class VideoService {
|
|
|
1065
1065
|
},
|
|
1066
1066
|
);
|
|
1067
1067
|
|
|
1068
|
-
const result = await this.sdk._fetch(
|
|
1068
|
+
const result = await this.sdk._fetch(
|
|
1069
|
+
`/video/${roomId}/livePresence`,
|
|
1070
|
+
'GET',
|
|
1071
|
+
);
|
|
1069
1072
|
return result;
|
|
1070
1073
|
}
|
|
1071
1074
|
|
|
@@ -1282,7 +1285,11 @@ export class VideoService {
|
|
|
1282
1285
|
},
|
|
1283
1286
|
);
|
|
1284
1287
|
|
|
1285
|
-
const result = await this.sdk._fetch(
|
|
1288
|
+
const result = await this.sdk._fetch(
|
|
1289
|
+
`/video/${roomId}/auto-name`,
|
|
1290
|
+
'POST',
|
|
1291
|
+
{},
|
|
1292
|
+
);
|
|
1286
1293
|
return result;
|
|
1287
1294
|
}
|
|
1288
1295
|
|
|
@@ -1431,10 +1438,19 @@ export class VideoService {
|
|
|
1431
1438
|
* the meet-hub plan — this file has no existing nested-namespace
|
|
1432
1439
|
* precedent, so flat matches every other method here.
|
|
1433
1440
|
*
|
|
1441
|
+
* @param {string} [userId] - Optional target userId (admin viewing another user's room, e.g. Setup -> Users -> Meet). Defaults to the calling user.
|
|
1434
1442
|
* @returns {Promise<{personalRoom: {id: string, slug: string, url: string|null, dialInPin: string, guestsCanStart: boolean}}>}
|
|
1435
1443
|
*/
|
|
1436
|
-
async getPersonalRoom() {
|
|
1437
|
-
const
|
|
1444
|
+
async getPersonalRoom(userId = null) {
|
|
1445
|
+
const params = { query: {} };
|
|
1446
|
+
if (userId) {
|
|
1447
|
+
this.sdk.validateParams(
|
|
1448
|
+
{ userId },
|
|
1449
|
+
{ userId: { type: 'string', required: true } },
|
|
1450
|
+
);
|
|
1451
|
+
params.query.userId = userId;
|
|
1452
|
+
}
|
|
1453
|
+
const result = await this.sdk._fetch('/video/personal-room', 'GET', params);
|
|
1438
1454
|
return result;
|
|
1439
1455
|
}
|
|
1440
1456
|
|
|
@@ -1445,9 +1461,11 @@ export class VideoService {
|
|
|
1445
1461
|
* @param {Object} [update]
|
|
1446
1462
|
* @param {string} [update.slug] - New slug (3-32 chars, lowercase/numbers/hyphens, not reserved). 409-equivalent BadRequestError on collision.
|
|
1447
1463
|
* @param {boolean} [update.guestsCanStart] - Whether guests can start the room without the host present.
|
|
1464
|
+
* @param {string} [update.password] - New static room passcode.
|
|
1465
|
+
* @param {string} [update.userId] - Optional target userId (admin editing another user's room). Defaults to the calling user.
|
|
1448
1466
|
* @returns {Promise<{personalRoom: {id: string, slug: string, url: string|null, dialInPin: string, guestsCanStart: boolean}}>}
|
|
1449
1467
|
*/
|
|
1450
|
-
async updatePersonalRoom({ slug, guestsCanStart, password } = {}) {
|
|
1468
|
+
async updatePersonalRoom({ slug, guestsCanStart, password, userId } = {}) {
|
|
1451
1469
|
const validationSchema = {};
|
|
1452
1470
|
if (slug !== undefined) validationSchema.slug = { type: 'string' };
|
|
1453
1471
|
if (guestsCanStart !== undefined)
|
|
@@ -1455,10 +1473,11 @@ export class VideoService {
|
|
|
1455
1473
|
// Static room passcode — 4-6 digits (api-enforced); applied to every
|
|
1456
1474
|
// session the room link mints.
|
|
1457
1475
|
if (password !== undefined) validationSchema.password = { type: 'string' };
|
|
1476
|
+
if (userId !== undefined) validationSchema.userId = { type: 'string' };
|
|
1458
1477
|
|
|
1459
1478
|
if (Object.keys(validationSchema).length > 0) {
|
|
1460
1479
|
this.sdk.validateParams(
|
|
1461
|
-
{ slug, guestsCanStart, password },
|
|
1480
|
+
{ slug, guestsCanStart, password, userId },
|
|
1462
1481
|
validationSchema,
|
|
1463
1482
|
);
|
|
1464
1483
|
}
|
|
@@ -1467,26 +1486,32 @@ export class VideoService {
|
|
|
1467
1486
|
if (slug !== undefined) body.slug = slug;
|
|
1468
1487
|
if (guestsCanStart !== undefined) body.guestsCanStart = guestsCanStart;
|
|
1469
1488
|
if (password !== undefined) body.password = password;
|
|
1489
|
+
if (userId !== undefined) body.userId = userId;
|
|
1470
1490
|
|
|
1471
1491
|
const params = { body };
|
|
1472
|
-
const result = await this.sdk._fetch(
|
|
1473
|
-
'/video/personal-room',
|
|
1474
|
-
'PUT',
|
|
1475
|
-
params,
|
|
1476
|
-
);
|
|
1492
|
+
const result = await this.sdk._fetch('/video/personal-room', 'PUT', params);
|
|
1477
1493
|
return result;
|
|
1478
1494
|
}
|
|
1479
1495
|
|
|
1480
1496
|
/**
|
|
1481
1497
|
* Regenerate the dial-in PIN for the calling user's personal meeting room.
|
|
1482
1498
|
*
|
|
1499
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1483
1500
|
* @returns {Promise<{personalRoom: {id: string, dialInPin: string}}>}
|
|
1484
1501
|
*/
|
|
1485
|
-
async regeneratePersonalRoomPin() {
|
|
1502
|
+
async regeneratePersonalRoomPin(userId = null) {
|
|
1503
|
+
const body = {};
|
|
1504
|
+
if (userId) {
|
|
1505
|
+
this.sdk.validateParams(
|
|
1506
|
+
{ userId },
|
|
1507
|
+
{ userId: { type: 'string', required: true } },
|
|
1508
|
+
);
|
|
1509
|
+
body.userId = userId;
|
|
1510
|
+
}
|
|
1486
1511
|
const result = await this.sdk._fetch(
|
|
1487
1512
|
'/video/personal-room/regenerate-pin',
|
|
1488
1513
|
'POST',
|
|
1489
|
-
{},
|
|
1514
|
+
{ body },
|
|
1490
1515
|
);
|
|
1491
1516
|
return result;
|
|
1492
1517
|
}
|
|
@@ -1495,17 +1520,23 @@ export class VideoService {
|
|
|
1495
1520
|
* Live availability dry-run for a personal-room slug (settings editor).
|
|
1496
1521
|
*
|
|
1497
1522
|
* @param {string} slug - Candidate slug.
|
|
1523
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1498
1524
|
* @returns {Promise<{slug: string, available: boolean, reason?: 'invalid'|'taken'}>}
|
|
1499
1525
|
*/
|
|
1500
|
-
async checkPersonalRoomSlug(slug) {
|
|
1526
|
+
async checkPersonalRoomSlug(slug, userId = null) {
|
|
1501
1527
|
this.sdk.validateParams(
|
|
1502
|
-
{ slug },
|
|
1503
|
-
{
|
|
1528
|
+
{ slug, userId },
|
|
1529
|
+
{
|
|
1530
|
+
slug: { type: 'string', required: true },
|
|
1531
|
+
userId: { type: 'string', required: false },
|
|
1532
|
+
},
|
|
1504
1533
|
);
|
|
1534
|
+
const query = { slug };
|
|
1535
|
+
if (userId) query.userId = userId;
|
|
1505
1536
|
const result = await this.sdk._fetch(
|
|
1506
|
-
|
|
1537
|
+
'/video/personal-room/slug-available',
|
|
1507
1538
|
'GET',
|
|
1508
|
-
{},
|
|
1539
|
+
{ query },
|
|
1509
1540
|
);
|
|
1510
1541
|
return result;
|
|
1511
1542
|
}
|
|
@@ -1515,13 +1546,22 @@ export class VideoService {
|
|
|
1515
1546
|
* meeting room (a separate secret from the dial-in PIN). Sessions minted
|
|
1516
1547
|
* after this use the new value.
|
|
1517
1548
|
*
|
|
1549
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1518
1550
|
* @returns {Promise<{personalRoom: {id: string, password: string}}>}
|
|
1519
1551
|
*/
|
|
1520
|
-
async regeneratePersonalRoomPassword() {
|
|
1552
|
+
async regeneratePersonalRoomPassword(userId = null) {
|
|
1553
|
+
const body = {};
|
|
1554
|
+
if (userId) {
|
|
1555
|
+
this.sdk.validateParams(
|
|
1556
|
+
{ userId },
|
|
1557
|
+
{ userId: { type: 'string', required: true } },
|
|
1558
|
+
);
|
|
1559
|
+
body.userId = userId;
|
|
1560
|
+
}
|
|
1521
1561
|
const result = await this.sdk._fetch(
|
|
1522
1562
|
'/video/personal-room/regenerate-password',
|
|
1523
1563
|
'POST',
|
|
1524
|
-
{},
|
|
1564
|
+
{ body },
|
|
1525
1565
|
);
|
|
1526
1566
|
return result;
|
|
1527
1567
|
}
|
package/services/voice.js
CHANGED
|
@@ -22,6 +22,34 @@ export class VoiceService {
|
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
async transcription({
|
|
26
|
+
cdrId,
|
|
27
|
+
callId,
|
|
28
|
+
action = 'start',
|
|
29
|
+
direction = 'sendrecv',
|
|
30
|
+
}) {
|
|
31
|
+
this.sdk.validateParams(
|
|
32
|
+
{ callId, cdrId, action, direction },
|
|
33
|
+
{
|
|
34
|
+
cdrId: { type: 'string', required: false },
|
|
35
|
+
callId: { type: 'string', required: false },
|
|
36
|
+
action: { type: 'string', required: false },
|
|
37
|
+
direction: { type: 'string', required: false },
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const params = {
|
|
42
|
+
body: { callId, cdrId, action, direction },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const result = await this.sdk._fetch(
|
|
46
|
+
`/voice/transcription/`,
|
|
47
|
+
'POST',
|
|
48
|
+
params,
|
|
49
|
+
);
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
25
53
|
async call({ to, from, destination, app, timeout, customHeaders, statusWebhook }) {
|
|
26
54
|
this.sdk.validateParams(
|
|
27
55
|
{ to, from, destination, app, timeout, customHeaders, statusWebhook },
|