@unboundcx/sdk 4.8.9 → 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/package.json +1 -1
- package/services/directory.js +73 -7
- package/services/inbox.js +54 -7
- package/services/messaging/EmailMailboxesService.js +49 -0
- package/services/taskRouter/CCService.js +302 -0
- package/services/taskRouter/MetricsService.js +54 -0
- package/services/taskRouter/TaskRouterService.js +2 -0
- package/services/video.js +186 -2
- 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/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/directory.js
CHANGED
|
@@ -15,27 +15,33 @@ export class DirectoryService {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Add a person or
|
|
19
|
-
* soft-deleted favorite on unique conflict.
|
|
18
|
+
* Add a person, company, user, or queue to directory favorites.
|
|
19
|
+
* Reactivates a soft-deleted favorite on unique conflict.
|
|
20
20
|
*
|
|
21
21
|
* @param {Object} params
|
|
22
|
-
* @param {string} params.objectType - 'person' or '
|
|
22
|
+
* @param {string} params.objectType - 'person', 'company', 'user', or 'queue' (required).
|
|
23
23
|
* @param {string} params.objectId - Id of the favorited record (required).
|
|
24
24
|
* @param {string[]} [params.channelIds] - Channel ids to pin for this favorite.
|
|
25
|
+
* @param {string} [params.channelId] - Channel id to pin for this favorite.
|
|
26
|
+
* @param {string} [params.numberField] - Number field to associate with this favorite.
|
|
25
27
|
* @returns {Promise<Object>} The created (or reactivated) favorite.
|
|
26
28
|
*/
|
|
27
|
-
async addFavorite({ objectType, objectId, channelIds }) {
|
|
29
|
+
async addFavorite({ objectType, objectId, channelIds, channelId, numberField }) {
|
|
28
30
|
this.sdk.validateParams(
|
|
29
|
-
{ objectType, objectId, channelIds },
|
|
31
|
+
{ objectType, objectId, channelIds, channelId, numberField },
|
|
30
32
|
{
|
|
31
33
|
objectType: { type: 'string', required: true },
|
|
32
34
|
objectId: { type: 'string', required: true },
|
|
33
35
|
channelIds: { type: 'array', required: false },
|
|
36
|
+
channelId: { type: 'string', required: false },
|
|
37
|
+
numberField: { type: 'string', required: false },
|
|
34
38
|
},
|
|
35
39
|
);
|
|
36
40
|
|
|
37
41
|
const body = { objectType, objectId };
|
|
38
42
|
if (channelIds !== undefined) body.channelIds = channelIds;
|
|
43
|
+
if (channelId !== undefined) body.channelId = channelId;
|
|
44
|
+
if (numberField !== undefined) body.numberField = numberField;
|
|
39
45
|
|
|
40
46
|
const params = { body };
|
|
41
47
|
|
|
@@ -49,21 +55,27 @@ export class DirectoryService {
|
|
|
49
55
|
* @param {string} favoriteId - Id of the favorite to update (required).
|
|
50
56
|
* @param {Object} params
|
|
51
57
|
* @param {string[]} [params.channelIds]
|
|
58
|
+
* @param {string} [params.channelId]
|
|
59
|
+
* @param {string} [params.numberField]
|
|
52
60
|
* @param {number} [params.sortOrder]
|
|
53
61
|
* @returns {Promise<Object>} The updated favorite.
|
|
54
62
|
*/
|
|
55
|
-
async updateFavorite(favoriteId, { channelIds, sortOrder } = {}) {
|
|
63
|
+
async updateFavorite(favoriteId, { channelIds, channelId, numberField, sortOrder } = {}) {
|
|
56
64
|
this.sdk.validateParams(
|
|
57
|
-
{ favoriteId, channelIds, sortOrder },
|
|
65
|
+
{ favoriteId, channelIds, channelId, numberField, sortOrder },
|
|
58
66
|
{
|
|
59
67
|
favoriteId: { type: 'string', required: true },
|
|
60
68
|
channelIds: { type: 'array', required: false },
|
|
69
|
+
channelId: { type: 'string', required: false },
|
|
70
|
+
numberField: { type: 'string', required: false },
|
|
61
71
|
sortOrder: { type: 'number', required: false },
|
|
62
72
|
},
|
|
63
73
|
);
|
|
64
74
|
|
|
65
75
|
const body = {};
|
|
66
76
|
if (channelIds !== undefined) body.channelIds = channelIds;
|
|
77
|
+
if (channelId !== undefined) body.channelId = channelId;
|
|
78
|
+
if (numberField !== undefined) body.numberField = numberField;
|
|
67
79
|
if (sortOrder !== undefined) body.sortOrder = sortOrder;
|
|
68
80
|
|
|
69
81
|
const params = { body };
|
|
@@ -121,4 +133,58 @@ export class DirectoryService {
|
|
|
121
133
|
);
|
|
122
134
|
return result;
|
|
123
135
|
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* List the current user's directory contacts.
|
|
139
|
+
*
|
|
140
|
+
* @returns {Promise<{contacts: Object[]}>}
|
|
141
|
+
*/
|
|
142
|
+
async listContacts() {
|
|
143
|
+
const result = await this.sdk._fetch('/directory/contacts', 'GET');
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Add a person or company to directory contacts.
|
|
149
|
+
*
|
|
150
|
+
* @param {Object} params
|
|
151
|
+
* @param {string} params.objectType - 'person' or 'company' (required).
|
|
152
|
+
* @param {string} params.objectId - Id of the contacted record (required).
|
|
153
|
+
* @returns {Promise<Object>} The created contact.
|
|
154
|
+
*/
|
|
155
|
+
async addContact({ objectType, objectId }) {
|
|
156
|
+
this.sdk.validateParams(
|
|
157
|
+
{ objectType, objectId },
|
|
158
|
+
{
|
|
159
|
+
objectType: { type: 'string', required: true },
|
|
160
|
+
objectId: { type: 'string', required: true },
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const params = { body: { objectType, objectId } };
|
|
165
|
+
|
|
166
|
+
const result = await this.sdk._fetch('/directory/contacts', 'POST', params);
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Remove a directory contact.
|
|
172
|
+
*
|
|
173
|
+
* @param {string} contactId - Id of the contact to remove (required).
|
|
174
|
+
* @returns {Promise<Object>}
|
|
175
|
+
*/
|
|
176
|
+
async removeContact(contactId) {
|
|
177
|
+
this.sdk.validateParams(
|
|
178
|
+
{ contactId },
|
|
179
|
+
{
|
|
180
|
+
contactId: { type: 'string', required: true },
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const result = await this.sdk._fetch(
|
|
185
|
+
`/directory/contacts/${contactId}`,
|
|
186
|
+
'DELETE',
|
|
187
|
+
);
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
124
190
|
}
|
package/services/inbox.js
CHANGED
|
@@ -9,21 +9,59 @@ export class InboxService {
|
|
|
9
9
|
*
|
|
10
10
|
* @param {Object} params
|
|
11
11
|
* @param {string|string[]} [params.types] - Source kinds to include
|
|
12
|
-
* ('call','voicemail','fax','sms'). Pass an array or a
|
|
13
|
-
* string; omit to include all kinds.
|
|
12
|
+
* ('call','voicemail','fax','sms','meeting'). Pass an array or a
|
|
13
|
+
* comma-joined string; omit to include all kinds.
|
|
14
14
|
* @param {number} [params.limit] - Max items to return.
|
|
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
|
|
|
@@ -82,10 +129,10 @@ export class InboxService {
|
|
|
82
129
|
}
|
|
83
130
|
|
|
84
131
|
/**
|
|
85
|
-
* Fetch inbox stats (calls/talk time/missed/unread voicemail) for
|
|
86
|
-
* current user.
|
|
132
|
+
* Fetch inbox stats (calls/talk time/missed/unread voicemail/meetings) for
|
|
133
|
+
* the current user.
|
|
87
134
|
*
|
|
88
|
-
* @returns {Promise<{callsToday: number, talkTimeSeconds: number, missedToday: number, unreadVoicemail: number, oldestUnreadVoicemailAt: string|null}>}
|
|
135
|
+
* @returns {Promise<{callsToday: number, talkTimeSeconds: number, missedToday: number, unreadVoicemail: number, oldestUnreadVoicemailAt: string|null, meetingsToday: number, meetingMinutesToday: number}>}
|
|
89
136
|
*/
|
|
90
137
|
async stats() {
|
|
91
138
|
const result = await this.sdk._fetch('/inbox/stats', 'GET');
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
export class CCService {
|
|
2
|
+
constructor(sdk) {
|
|
3
|
+
this.sdk = sdk;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the caller's Contact Center queue scope + role.
|
|
8
|
+
* Managers see every non-deleted queue; agents see only the queues they
|
|
9
|
+
* belong to (queueUsers).
|
|
10
|
+
*
|
|
11
|
+
* @returns {Promise<Object>} result
|
|
12
|
+
* @returns {boolean} result.isManager - Whether the caller has queue-manager scope
|
|
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, slaTargetPct, timezone}]
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const scope = await sdk.taskRouter.cc.getScope();
|
|
18
|
+
* console.log(scope.isManager, scope.queues.length);
|
|
19
|
+
*/
|
|
20
|
+
async getScope() {
|
|
21
|
+
const result = await this.sdk._fetch('/taskRouter/cc/scope', 'GET', {});
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get a live Contact Center snapshot (KPIs, per-queue summaries, team roster
|
|
27
|
+
* with active tasks) scoped to a set of queues.
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} [options] - Parameters
|
|
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
|
+
* @returns {Promise<Object>} result
|
|
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, slaThreshold, slaTargetPct, timezone, health)
|
|
34
|
+
* @returns {Array<Object>} result.team - Team roster with active tasks
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const snapshot = await sdk.taskRouter.cc.getSnapshot({ queueIds: ['q1', 'q2'] });
|
|
38
|
+
* console.log(snapshot.kpis.inQueueNow);
|
|
39
|
+
*/
|
|
40
|
+
async getSnapshot(options = {}) {
|
|
41
|
+
const { queueIds } = options;
|
|
42
|
+
|
|
43
|
+
this.sdk.validateParams(
|
|
44
|
+
{ queueIds },
|
|
45
|
+
{
|
|
46
|
+
queueIds: { type: 'array', required: false },
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const params = {};
|
|
51
|
+
if (queueIds && queueIds.length) {
|
|
52
|
+
params.query = { queueIds: queueIds.join(',') };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = await this.sdk._fetch(
|
|
56
|
+
'/taskRouter/cc/snapshot',
|
|
57
|
+
'GET',
|
|
58
|
+
params,
|
|
59
|
+
);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get on-queue session history for a worker (self allowed; another
|
|
65
|
+
* worker's sessions require the queue-manager scope).
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} [options] - Parameters
|
|
68
|
+
* @param {string} [options.workerId] - Worker id to fetch sessions for (defaults to the caller's own worker)
|
|
69
|
+
* @param {string} [options.from] - ISO-8601 range start
|
|
70
|
+
* @param {string} [options.to] - ISO-8601 range end
|
|
71
|
+
* @returns {Promise<Object>} result
|
|
72
|
+
* @returns {Array<Object>} result.sessions - [{id, startedAt, endedAt, onQueueSec, breakSec, doneCount}]
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* const { sessions } = await sdk.taskRouter.cc.getSessions({ workerId: 'w1', from: '2026-08-12T00:00:00Z', to: '2026-08-19T00:00:00Z' });
|
|
76
|
+
*/
|
|
77
|
+
async getSessions(options = {}) {
|
|
78
|
+
const { workerId, from, to } = options;
|
|
79
|
+
|
|
80
|
+
this.sdk.validateParams(
|
|
81
|
+
{ workerId, from, to },
|
|
82
|
+
{
|
|
83
|
+
workerId: { type: 'string', required: false },
|
|
84
|
+
from: { type: 'string', required: false },
|
|
85
|
+
to: { type: 'string', required: false },
|
|
86
|
+
},
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const query = {};
|
|
90
|
+
if (workerId) query.workerId = workerId;
|
|
91
|
+
if (from) query.from = from;
|
|
92
|
+
if (to) query.to = to;
|
|
93
|
+
|
|
94
|
+
const result = await this.sdk._fetch('/taskRouter/cc/sessions', 'GET', {
|
|
95
|
+
query,
|
|
96
|
+
});
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get windowed composite agent rankings (top/struggling) per queue + an
|
|
102
|
+
* 'all' rollup, scored from sentiment/SLA/volume/acceptance. `struggling`
|
|
103
|
+
* arrays are only present when the caller has the queue-manager scope
|
|
104
|
+
* (see `strugglingIncluded` on the result).
|
|
105
|
+
*
|
|
106
|
+
* @param {Object} [options] - Parameters
|
|
107
|
+
* @param {string[]} [options.queueIds] - Queue ids to scope to (must be a subset of the caller's accessible queues). Omit/empty for full scope.
|
|
108
|
+
* @param {string} options.from - ISO-8601 window start
|
|
109
|
+
* @param {string} options.to - ISO-8601 window end
|
|
110
|
+
* @returns {Promise<Object>} result
|
|
111
|
+
* @returns {Object} result.queues - Per-queue rankings, keyed by queueId: `{ top: [{workerId,name,score}], struggling?: [...] }`
|
|
112
|
+
* @returns {Object} result.all - Same shape, aggregated across every scoped queue
|
|
113
|
+
* @returns {boolean} result.strugglingIncluded - Whether `struggling` arrays were included
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const { queues, all } = await sdk.taskRouter.cc.getRankings({
|
|
117
|
+
* queueIds: ['q1'],
|
|
118
|
+
* from: '2026-08-12T00:00:00Z',
|
|
119
|
+
* to: '2026-08-19T00:00:00Z',
|
|
120
|
+
* });
|
|
121
|
+
* console.log(all.top[0].name, all.top[0].score);
|
|
122
|
+
*/
|
|
123
|
+
async getRankings(options = {}) {
|
|
124
|
+
const { queueIds, from, to } = options;
|
|
125
|
+
|
|
126
|
+
this.sdk.validateParams(
|
|
127
|
+
{ queueIds, from, to },
|
|
128
|
+
{
|
|
129
|
+
queueIds: { type: 'array', required: false },
|
|
130
|
+
from: { type: 'string', required: true },
|
|
131
|
+
to: { type: 'string', required: true },
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const query = { from, to };
|
|
136
|
+
if (queueIds && queueIds.length) {
|
|
137
|
+
query.queueIds = queueIds.join(',');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const result = await this.sdk._fetch('/taskRouter/cc/rankings', 'GET', {
|
|
141
|
+
query,
|
|
142
|
+
});
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Set a queue's composite ranking-weights override. Manager-only
|
|
148
|
+
* (`taskrouter:queue:manage`). Weights must be integers 0-100 that sum to
|
|
149
|
+
* exactly 100.
|
|
150
|
+
*
|
|
151
|
+
* @param {Object} options - Parameters
|
|
152
|
+
* @param {string} options.queueId - Queue id to update
|
|
153
|
+
* @param {Object} options.weights - `{sentiment, aht, volume, acceptance}` ints summing to 100
|
|
154
|
+
* @returns {Promise<Object>} result
|
|
155
|
+
* @returns {string} result.queueId
|
|
156
|
+
* @returns {Object} result.rankingWeights - The stored weights
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* await sdk.taskRouter.cc.setQueueRankingWeights({
|
|
160
|
+
* queueId: 'q1',
|
|
161
|
+
* weights: { sentiment: 40, aht: 30, volume: 5, acceptance: 25 },
|
|
162
|
+
* });
|
|
163
|
+
*/
|
|
164
|
+
async setQueueRankingWeights(options = {}) {
|
|
165
|
+
const { queueId, weights } = options;
|
|
166
|
+
|
|
167
|
+
this.sdk.validateParams(
|
|
168
|
+
{ queueId, weights },
|
|
169
|
+
{
|
|
170
|
+
queueId: { type: 'string', required: true },
|
|
171
|
+
weights: { type: 'object', required: true },
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const result = await this.sdk._fetch(
|
|
176
|
+
`/taskRouter/cc/queues/${queueId}/rankingWeights`,
|
|
177
|
+
'PUT',
|
|
178
|
+
{ body: weights },
|
|
179
|
+
);
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get one agent's Contact Center performance summary (KPIs, per-day
|
|
185
|
+
* charts, live tasks, on-queue sessions) over a date/date-range, with a
|
|
186
|
+
* comparison window for deltas. Self allowed; another worker's summary
|
|
187
|
+
* requires the queue-manager scope.
|
|
188
|
+
*
|
|
189
|
+
* @param {Object} options - Parameters
|
|
190
|
+
* @param {string} options.workerId - Worker id to summarize
|
|
191
|
+
* @param {string} options.from - ISO-8601 window start
|
|
192
|
+
* @param {string} options.to - ISO-8601 window end
|
|
193
|
+
* @param {string} [options.compareFrom] - ISO-8601 comparison window start (defaults to the preceding equal-length period)
|
|
194
|
+
* @param {string} [options.compareTo] - ISO-8601 comparison window end
|
|
195
|
+
* @returns {Promise<Object>} result
|
|
196
|
+
* @returns {Object} result.kpis - tasksHandled, offersAccepted, avgHandleSec, slaMet, avgSentiment, composite, onQueue
|
|
197
|
+
* @returns {Array<Object>} result.tasksPerDay - [{date, count}]
|
|
198
|
+
* @returns {Array<Object>} result.trend - [{date, sentiment, slaPct}]
|
|
199
|
+
* @returns {Array<Object>} result.liveNow - Current tasks (only when the window includes today)
|
|
200
|
+
* @returns {Array<Object>} result.sessions - On-queue session log
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* const summary = await sdk.taskRouter.cc.getAgentSummary({
|
|
204
|
+
* workerId: 'w1',
|
|
205
|
+
* from: '2026-08-12T00:00:00Z',
|
|
206
|
+
* to: '2026-08-19T00:00:00Z',
|
|
207
|
+
* });
|
|
208
|
+
* console.log(summary.kpis.tasksHandled.value);
|
|
209
|
+
*/
|
|
210
|
+
async getAgentSummary(options = {}) {
|
|
211
|
+
const { workerId, from, to, compareFrom, compareTo } = options;
|
|
212
|
+
|
|
213
|
+
this.sdk.validateParams(
|
|
214
|
+
{ workerId, from, to, compareFrom, compareTo },
|
|
215
|
+
{
|
|
216
|
+
workerId: { type: 'string', required: true },
|
|
217
|
+
from: { type: 'string', required: true },
|
|
218
|
+
to: { type: 'string', required: true },
|
|
219
|
+
compareFrom: { type: 'string', required: false },
|
|
220
|
+
compareTo: { type: 'string', required: false },
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const query = { from, to };
|
|
225
|
+
if (compareFrom) query.compareFrom = compareFrom;
|
|
226
|
+
if (compareTo) query.compareTo = compareTo;
|
|
227
|
+
|
|
228
|
+
const result = await this.sdk._fetch(
|
|
229
|
+
`/taskRouter/cc/agents/${workerId}/summary`,
|
|
230
|
+
'GET',
|
|
231
|
+
{ query },
|
|
232
|
+
);
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Log a worker into or out of a queue. Manager-only
|
|
238
|
+
* (`taskrouter:queue:manage`). Mutates the worker's queue membership
|
|
239
|
+
* through task-router (audited).
|
|
240
|
+
*
|
|
241
|
+
* @param {Object} options - Parameters
|
|
242
|
+
* @param {string} options.workerId - Worker id to update
|
|
243
|
+
* @param {string} options.queueId - Queue id to log in/out of
|
|
244
|
+
* @param {'login'|'logout'} options.action - Whether to add or remove the queue
|
|
245
|
+
* @returns {Promise<Object>} result
|
|
246
|
+
* @returns {string} result.workerId
|
|
247
|
+
* @returns {string} result.status
|
|
248
|
+
* @returns {Array<string>} result.queues - The worker's updated queue list
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* await sdk.taskRouter.cc.setWorkerQueue({ workerId: 'w1', queueId: 'q1', action: 'login' });
|
|
252
|
+
*/
|
|
253
|
+
async setWorkerQueue(options = {}) {
|
|
254
|
+
const { workerId, queueId, action } = options;
|
|
255
|
+
|
|
256
|
+
this.sdk.validateParams(
|
|
257
|
+
{ workerId, queueId, action },
|
|
258
|
+
{
|
|
259
|
+
workerId: { type: 'string', required: true },
|
|
260
|
+
queueId: { type: 'string', required: true },
|
|
261
|
+
action: { type: 'string', required: true },
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const result = await this.sdk._fetch(
|
|
266
|
+
`/taskRouter/cc/workers/${workerId}/queues`,
|
|
267
|
+
'PUT',
|
|
268
|
+
{ body: { queueId, action } },
|
|
269
|
+
);
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Force a worker offline (out of every queue), closing their on-queue
|
|
275
|
+
* session. Manager-only (`taskrouter:queue:manage`, audited).
|
|
276
|
+
*
|
|
277
|
+
* @param {Object} options - Parameters
|
|
278
|
+
* @param {string} options.workerId - Worker id to log out
|
|
279
|
+
* @returns {Promise<Object>} result
|
|
280
|
+
* @returns {string} result.workerId
|
|
281
|
+
* @returns {string} result.status
|
|
282
|
+
* @returns {Array<string>} result.queues
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* await sdk.taskRouter.cc.forceLogoutWorker({ workerId: 'w1' });
|
|
286
|
+
*/
|
|
287
|
+
async forceLogoutWorker(options = {}) {
|
|
288
|
+
const { workerId } = options;
|
|
289
|
+
|
|
290
|
+
this.sdk.validateParams(
|
|
291
|
+
{ workerId },
|
|
292
|
+
{ workerId: { type: 'string', required: true } },
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const result = await this.sdk._fetch(
|
|
296
|
+
`/taskRouter/cc/workers/${workerId}/forceLogout`,
|
|
297
|
+
'POST',
|
|
298
|
+
{},
|
|
299
|
+
);
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -108,4 +108,58 @@ export class MetricsService {
|
|
|
108
108
|
);
|
|
109
109
|
return result;
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get windowed queue/company metrics with a compare-window delta, per
|
|
114
|
+
* queue + an 'all' rollup (avg wait, avg handle, service level, longest
|
|
115
|
+
* wait, live depth/workers, and a waiting-count sparkline).
|
|
116
|
+
*
|
|
117
|
+
* @param {Object} params - Parameters
|
|
118
|
+
* @param {string[]} [params.queueIds] - Queue ids to scope to. Omit/empty for all queues.
|
|
119
|
+
* @param {string} params.from - ISO-8601 window start
|
|
120
|
+
* @param {string} params.to - ISO-8601 window end
|
|
121
|
+
* @param {string} params.compareFrom - ISO-8601 compare-window start
|
|
122
|
+
* @param {string} params.compareTo - ISO-8601 compare-window end
|
|
123
|
+
* @returns {Promise<Object>} result
|
|
124
|
+
* @returns {Object} result.window - `{from, to}`
|
|
125
|
+
* @returns {Object} result.compare - `{from, to}`
|
|
126
|
+
* @returns {Object} result.all - Rollup across every scoped queue (avgWaitSec, avgHandleSec, serviceLevelPct, longestWaitSec, depth, workersAvailable, workersTotal, waitingSparkline, deltas)
|
|
127
|
+
* @returns {Object} result.queues - Same shape as `result.all`, keyed by queueId
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const { all, queues } = await sdk.taskRouter.metrics.getWindow({
|
|
131
|
+
* queueIds: ['q1', 'q2'],
|
|
132
|
+
* from: '2026-08-19T22:00:00Z',
|
|
133
|
+
* to: '2026-08-19T23:00:00Z',
|
|
134
|
+
* compareFrom: '2026-08-19T21:00:00Z',
|
|
135
|
+
* compareTo: '2026-08-19T22:00:00Z',
|
|
136
|
+
* });
|
|
137
|
+
* console.log(all.serviceLevelPct, all.deltas.serviceLevelPct);
|
|
138
|
+
*/
|
|
139
|
+
async getWindow(params = {}) {
|
|
140
|
+
const { queueIds, from, to, compareFrom, compareTo } = params;
|
|
141
|
+
|
|
142
|
+
this.sdk.validateParams(
|
|
143
|
+
{ queueIds, from, to, compareFrom, compareTo },
|
|
144
|
+
{
|
|
145
|
+
queueIds: { type: 'array', required: false },
|
|
146
|
+
from: { type: 'string', required: true },
|
|
147
|
+
to: { type: 'string', required: true },
|
|
148
|
+
compareFrom: { type: 'string', required: false },
|
|
149
|
+
compareTo: { type: 'string', required: false },
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const query = { from, to };
|
|
154
|
+
if (queueIds && queueIds.length) query.queueIds = queueIds.join(',');
|
|
155
|
+
if (compareFrom) query.compareFrom = compareFrom;
|
|
156
|
+
if (compareTo) query.compareTo = compareTo;
|
|
157
|
+
|
|
158
|
+
const result = await this.sdk._fetch(
|
|
159
|
+
'/taskRouter/metrics/window',
|
|
160
|
+
'GET',
|
|
161
|
+
{ query },
|
|
162
|
+
);
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
111
165
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WorkerService } from './WorkerService.js';
|
|
2
2
|
import { TaskService } from './TaskService.js';
|
|
3
3
|
import { MetricsService } from './MetricsService.js';
|
|
4
|
+
import { CCService } from './CCService.js';
|
|
4
5
|
|
|
5
6
|
export class TaskRouterService {
|
|
6
7
|
constructor(sdk) {
|
|
@@ -8,5 +9,6 @@ export class TaskRouterService {
|
|
|
8
9
|
this.worker = new WorkerService(sdk);
|
|
9
10
|
this.task = new TaskService(sdk);
|
|
10
11
|
this.metrics = new MetricsService(sdk);
|
|
12
|
+
this.cc = new CCService(sdk);
|
|
11
13
|
}
|
|
12
14
|
}
|
package/services/video.js
CHANGED
|
@@ -230,6 +230,7 @@ export class VideoService {
|
|
|
230
230
|
calendarProvider,
|
|
231
231
|
vocabularyTerms,
|
|
232
232
|
shareOcrEnabled,
|
|
233
|
+
earlyJoinMinutes,
|
|
233
234
|
}) {
|
|
234
235
|
this.sdk.validateParams(
|
|
235
236
|
{
|
|
@@ -259,6 +260,7 @@ export class VideoService {
|
|
|
259
260
|
calendarProvider,
|
|
260
261
|
vocabularyTerms,
|
|
261
262
|
shareOcrEnabled,
|
|
263
|
+
earlyJoinMinutes,
|
|
262
264
|
},
|
|
263
265
|
{
|
|
264
266
|
name: { type: 'string', required: false },
|
|
@@ -287,6 +289,9 @@ export class VideoService {
|
|
|
287
289
|
calendarProvider: { type: 'string', required: false },
|
|
288
290
|
vocabularyTerms: { type: 'array', required: false },
|
|
289
291
|
shareOcrEnabled: { type: 'boolean', required: false },
|
|
292
|
+
// 0 = strict at startTime, 5 = 5-min early window (api rejects
|
|
293
|
+
// other values); omit for no schedule-window enforcement.
|
|
294
|
+
earlyJoinMinutes: { type: 'number', required: false },
|
|
290
295
|
},
|
|
291
296
|
);
|
|
292
297
|
const params = {
|
|
@@ -317,6 +322,7 @@ export class VideoService {
|
|
|
317
322
|
calendarProvider,
|
|
318
323
|
vocabularyTerms,
|
|
319
324
|
shareOcrEnabled,
|
|
325
|
+
earlyJoinMinutes,
|
|
320
326
|
},
|
|
321
327
|
};
|
|
322
328
|
const result = await this.sdk._fetch(`/video`, 'POST', params);
|
|
@@ -362,6 +368,8 @@ export class VideoService {
|
|
|
362
368
|
validationSchema.vocabularyTerms = { type: 'array' };
|
|
363
369
|
if ('shareOcrEnabled' in update)
|
|
364
370
|
validationSchema.shareOcrEnabled = { type: 'boolean' };
|
|
371
|
+
if ('earlyJoinMinutes' in update)
|
|
372
|
+
validationSchema.earlyJoinMinutes = { type: 'number' };
|
|
365
373
|
|
|
366
374
|
if (Object.keys(validationSchema).length > 0) {
|
|
367
375
|
this.sdk.validateParams(update, validationSchema);
|
|
@@ -1057,7 +1065,10 @@ export class VideoService {
|
|
|
1057
1065
|
},
|
|
1058
1066
|
);
|
|
1059
1067
|
|
|
1060
|
-
const result = await this.sdk._fetch(
|
|
1068
|
+
const result = await this.sdk._fetch(
|
|
1069
|
+
`/video/${roomId}/livePresence`,
|
|
1070
|
+
'GET',
|
|
1071
|
+
);
|
|
1061
1072
|
return result;
|
|
1062
1073
|
}
|
|
1063
1074
|
|
|
@@ -1274,7 +1285,11 @@ export class VideoService {
|
|
|
1274
1285
|
},
|
|
1275
1286
|
);
|
|
1276
1287
|
|
|
1277
|
-
const result = await this.sdk._fetch(
|
|
1288
|
+
const result = await this.sdk._fetch(
|
|
1289
|
+
`/video/${roomId}/auto-name`,
|
|
1290
|
+
'POST',
|
|
1291
|
+
{},
|
|
1292
|
+
);
|
|
1278
1293
|
return result;
|
|
1279
1294
|
}
|
|
1280
1295
|
|
|
@@ -1411,4 +1426,173 @@ export class VideoService {
|
|
|
1411
1426
|
);
|
|
1412
1427
|
return result;
|
|
1413
1428
|
}
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* Get (or lazily create) the calling user's personal meeting room for this
|
|
1432
|
+
* account. Every account user has exactly one; the first call provisions
|
|
1433
|
+
* it server-side.
|
|
1434
|
+
*
|
|
1435
|
+
* NOTE: implemented flat (`getPersonalRoom`/`updatePersonalRoom`/
|
|
1436
|
+
* `regeneratePersonalRoomPin`/`resolvePersonalRoom`) rather than the
|
|
1437
|
+
* `sdk.video.personalRoom.{get,update,regeneratePin}` namespace named in
|
|
1438
|
+
* the meet-hub plan — this file has no existing nested-namespace
|
|
1439
|
+
* precedent, so flat matches every other method here.
|
|
1440
|
+
*
|
|
1441
|
+
* @param {string} [userId] - Optional target userId (admin viewing another user's room, e.g. Setup -> Users -> Meet). Defaults to the calling user.
|
|
1442
|
+
* @returns {Promise<{personalRoom: {id: string, slug: string, url: string|null, dialInPin: string, guestsCanStart: boolean}}>}
|
|
1443
|
+
*/
|
|
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);
|
|
1454
|
+
return result;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
/**
|
|
1458
|
+
* Update the calling user's personal meeting room (slug and/or
|
|
1459
|
+
* guests-can-start). Omit a field to leave it unchanged.
|
|
1460
|
+
*
|
|
1461
|
+
* @param {Object} [update]
|
|
1462
|
+
* @param {string} [update.slug] - New slug (3-32 chars, lowercase/numbers/hyphens, not reserved). 409-equivalent BadRequestError on collision.
|
|
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.
|
|
1466
|
+
* @returns {Promise<{personalRoom: {id: string, slug: string, url: string|null, dialInPin: string, guestsCanStart: boolean}}>}
|
|
1467
|
+
*/
|
|
1468
|
+
async updatePersonalRoom({ slug, guestsCanStart, password, userId } = {}) {
|
|
1469
|
+
const validationSchema = {};
|
|
1470
|
+
if (slug !== undefined) validationSchema.slug = { type: 'string' };
|
|
1471
|
+
if (guestsCanStart !== undefined)
|
|
1472
|
+
validationSchema.guestsCanStart = { type: 'boolean' };
|
|
1473
|
+
// Static room passcode — 4-6 digits (api-enforced); applied to every
|
|
1474
|
+
// session the room link mints.
|
|
1475
|
+
if (password !== undefined) validationSchema.password = { type: 'string' };
|
|
1476
|
+
if (userId !== undefined) validationSchema.userId = { type: 'string' };
|
|
1477
|
+
|
|
1478
|
+
if (Object.keys(validationSchema).length > 0) {
|
|
1479
|
+
this.sdk.validateParams(
|
|
1480
|
+
{ slug, guestsCanStart, password, userId },
|
|
1481
|
+
validationSchema,
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
const body = {};
|
|
1486
|
+
if (slug !== undefined) body.slug = slug;
|
|
1487
|
+
if (guestsCanStart !== undefined) body.guestsCanStart = guestsCanStart;
|
|
1488
|
+
if (password !== undefined) body.password = password;
|
|
1489
|
+
if (userId !== undefined) body.userId = userId;
|
|
1490
|
+
|
|
1491
|
+
const params = { body };
|
|
1492
|
+
const result = await this.sdk._fetch('/video/personal-room', 'PUT', params);
|
|
1493
|
+
return result;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Regenerate the dial-in PIN for the calling user's personal meeting room.
|
|
1498
|
+
*
|
|
1499
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1500
|
+
* @returns {Promise<{personalRoom: {id: string, dialInPin: string}}>}
|
|
1501
|
+
*/
|
|
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
|
+
}
|
|
1511
|
+
const result = await this.sdk._fetch(
|
|
1512
|
+
'/video/personal-room/regenerate-pin',
|
|
1513
|
+
'POST',
|
|
1514
|
+
{ body },
|
|
1515
|
+
);
|
|
1516
|
+
return result;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Live availability dry-run for a personal-room slug (settings editor).
|
|
1521
|
+
*
|
|
1522
|
+
* @param {string} slug - Candidate slug.
|
|
1523
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1524
|
+
* @returns {Promise<{slug: string, available: boolean, reason?: 'invalid'|'taken'}>}
|
|
1525
|
+
*/
|
|
1526
|
+
async checkPersonalRoomSlug(slug, userId = null) {
|
|
1527
|
+
this.sdk.validateParams(
|
|
1528
|
+
{ slug, userId },
|
|
1529
|
+
{
|
|
1530
|
+
slug: { type: 'string', required: true },
|
|
1531
|
+
userId: { type: 'string', required: false },
|
|
1532
|
+
},
|
|
1533
|
+
);
|
|
1534
|
+
const query = { slug };
|
|
1535
|
+
if (userId) query.userId = userId;
|
|
1536
|
+
const result = await this.sdk._fetch(
|
|
1537
|
+
'/video/personal-room/slug-available',
|
|
1538
|
+
'GET',
|
|
1539
|
+
{ query },
|
|
1540
|
+
);
|
|
1541
|
+
return result;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Regenerate the static web passcode for the calling user's personal
|
|
1546
|
+
* meeting room (a separate secret from the dial-in PIN). Sessions minted
|
|
1547
|
+
* after this use the new value.
|
|
1548
|
+
*
|
|
1549
|
+
* @param {string} [userId] - Optional target userId (admin action). Defaults to the calling user.
|
|
1550
|
+
* @returns {Promise<{personalRoom: {id: string, password: string}}>}
|
|
1551
|
+
*/
|
|
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
|
+
}
|
|
1561
|
+
const result = await this.sdk._fetch(
|
|
1562
|
+
'/video/personal-room/regenerate-password',
|
|
1563
|
+
'POST',
|
|
1564
|
+
{ body },
|
|
1565
|
+
);
|
|
1566
|
+
return result;
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Resolve a personal-room slug to a live session (join page). Guest-capable
|
|
1571
|
+
* — mints/claims a fresh meeting if none is live, or returns the already
|
|
1572
|
+
* -claimed session; if the caller is an unauthenticated guest and the room
|
|
1573
|
+
* doesn't allow guests to start, returns `waitingForHost: true` instead.
|
|
1574
|
+
* Guests only receive `password` when they supply the room's static
|
|
1575
|
+
* passcode; otherwise `passwordRequired: true` is returned and the join
|
|
1576
|
+
* page should prompt.
|
|
1577
|
+
*
|
|
1578
|
+
* @param {string} slug - The personal room's slug.
|
|
1579
|
+
* @param {{password?: string}} [options] - The room's static passcode, when known.
|
|
1580
|
+
* @returns {Promise<{claimed: boolean, meetingId?: string, friendlyName?: string, password?: string, passwordRequired?: boolean, waitingForHost?: boolean}>}
|
|
1581
|
+
*/
|
|
1582
|
+
async resolvePersonalRoom(slug, { password } = {}) {
|
|
1583
|
+
this.sdk.validateParams(
|
|
1584
|
+
{ slug, password },
|
|
1585
|
+
{
|
|
1586
|
+
slug: { type: 'string', required: true },
|
|
1587
|
+
password: { type: 'string', required: false },
|
|
1588
|
+
},
|
|
1589
|
+
);
|
|
1590
|
+
|
|
1591
|
+
const result = await this.sdk._fetch(
|
|
1592
|
+
`/video/personal-room/resolve/${slug}`,
|
|
1593
|
+
'POST',
|
|
1594
|
+
{ body: { password } },
|
|
1595
|
+
);
|
|
1596
|
+
return result;
|
|
1597
|
+
}
|
|
1414
1598
|
}
|
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 },
|