@unboundcx/sdk 4.1.2 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/index.js +3 -0
- package/package.json +1 -1
- package/services/permissions.js +377 -0
package/README.md
CHANGED
|
@@ -176,6 +176,36 @@ await api.objects.describe('contacts'); // Get schema
|
|
|
176
176
|
await api.objects.list(); // List all object types
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
+
#### Live Queries (`api.objects.liveQuery`)
|
|
180
|
+
|
|
181
|
+
Real-time, server-evaluated subscriptions over App1 Database objects. The
|
|
182
|
+
server matches every mutation against your filter and pushes only relevant
|
|
183
|
+
events — no client-side polling or firehose filtering.
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
const handle = await api.objects.liveQuery({
|
|
187
|
+
socket, // an authed socket.io-client instance (required until the SDK ships its own transport)
|
|
188
|
+
object: 'contacts',
|
|
189
|
+
filter: { companyId: 'company-123' }, // bare value = equals; 'op::term' strings for other operators
|
|
190
|
+
onEvent: (frame) => {
|
|
191
|
+
// frame.type: 'enter' | 'change' | 'leave' | 'refresh' | 'resync' | 'revoked'
|
|
192
|
+
// 'enter' -> frame.record (full row now matches your filter)
|
|
193
|
+
// 'change' -> frame.changedFields ONLY (patch, never the full row)
|
|
194
|
+
// 'leave' -> frame.recordId no longer matches (or was deleted)
|
|
195
|
+
// 'refresh'/'resync' -> re-run your query (coarse mode or gap recovery)
|
|
196
|
+
},
|
|
197
|
+
onStateChange: (state) => {}, // 'active' | 'resubscribing' | 'revoked'
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
handle.unsubscribe(); // always tear down when done
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Notes: the resolved `handle.mode` is `'fine'` (row-level events) or
|
|
204
|
+
`'coarse'` (debounced refresh hints — used when the filter isn't
|
|
205
|
+
row-evaluable). Heartbeats, reconnect-resubscribe, and sequence-gap resync
|
|
206
|
+
are handled internally. Server caps: 25 subscriptions per socket, 500 per
|
|
207
|
+
account.
|
|
208
|
+
|
|
179
209
|
#### Messaging (`api.messaging`)
|
|
180
210
|
|
|
181
211
|
```javascript
|
package/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import { EngagementMetricsService } from './services/engagementMetrics.js';
|
|
|
27
27
|
import { TaskRouterService } from './services/taskRouter.js';
|
|
28
28
|
import { KnowledgeBaseService } from './services/knowledgeBase.js';
|
|
29
29
|
import { FaxService } from './services/fax.js';
|
|
30
|
+
import { PermissionsService } from './services/permissions.js';
|
|
30
31
|
|
|
31
32
|
class UnboundSDK extends BaseSDK {
|
|
32
33
|
constructor(options = {}) {
|
|
@@ -95,6 +96,7 @@ class UnboundSDK extends BaseSDK {
|
|
|
95
96
|
this.taskRouter = new TaskRouterService(this);
|
|
96
97
|
this.knowledgeBase = new KnowledgeBaseService(this);
|
|
97
98
|
this.fax = new FaxService(this);
|
|
99
|
+
this.permissions = new PermissionsService(this);
|
|
98
100
|
|
|
99
101
|
// Add additional services that might be missing
|
|
100
102
|
this._initializeAdditionalServices();
|
|
@@ -274,4 +276,5 @@ export { TaskRouterService } from './services/taskRouter.js';
|
|
|
274
276
|
export { WorkerService } from './services/taskRouter/WorkerService.js';
|
|
275
277
|
export { KnowledgeBaseService } from './services/knowledgeBase.js';
|
|
276
278
|
export { FaxService } from './services/fax.js';
|
|
279
|
+
export { PermissionsService } from './services/permissions.js';
|
|
277
280
|
export { BaseSDK } from './base.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
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",
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
export class PermissionsService {
|
|
2
|
+
constructor(sdk) {
|
|
3
|
+
this.sdk = sdk;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* List permission groups
|
|
8
|
+
* @returns {Promise<Object>} Object with results: Array of permission groups
|
|
9
|
+
* @example
|
|
10
|
+
* const { results } = await sdk.permissions.listGroups();
|
|
11
|
+
*/
|
|
12
|
+
async listGroups() {
|
|
13
|
+
const result = await this.sdk._fetch('/permissions/groups', 'GET');
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create a new permission group
|
|
19
|
+
* @param {Object} group - Group configuration
|
|
20
|
+
* @param {string} group.name - Group name (required)
|
|
21
|
+
* @param {string} group.description - Group description
|
|
22
|
+
* @returns {Promise<Object>} Created group
|
|
23
|
+
* @example
|
|
24
|
+
* await sdk.permissions.createGroup({
|
|
25
|
+
* name: 'Support Leads',
|
|
26
|
+
* description: 'Escalation-tier support agents',
|
|
27
|
+
* });
|
|
28
|
+
*/
|
|
29
|
+
async createGroup({ name, description }) {
|
|
30
|
+
this.sdk.validateParams(
|
|
31
|
+
{ name, description },
|
|
32
|
+
{
|
|
33
|
+
name: { type: 'string', required: true },
|
|
34
|
+
description: { type: 'string', required: false },
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const groupData = { name };
|
|
39
|
+
if (description !== undefined) groupData.description = description;
|
|
40
|
+
|
|
41
|
+
const params = {
|
|
42
|
+
body: groupData,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const result = await this.sdk._fetch('/permissions/groups', 'POST', params);
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Update an existing permission group
|
|
51
|
+
* @param {string} groupId - Group ID to update
|
|
52
|
+
* @param {Object} data - Fields to update (e.g. name, description)
|
|
53
|
+
* @returns {Promise<Object>} Updated group
|
|
54
|
+
* @example
|
|
55
|
+
* await sdk.permissions.updateGroup('group-123', { description: 'Updated' });
|
|
56
|
+
*/
|
|
57
|
+
async updateGroup(groupId, data) {
|
|
58
|
+
groupId = String(groupId);
|
|
59
|
+
this.sdk.validateParams(
|
|
60
|
+
{ groupId },
|
|
61
|
+
{
|
|
62
|
+
groupId: { type: 'string', required: true },
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const params = {
|
|
67
|
+
body: data,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const result = await this.sdk._fetch(
|
|
71
|
+
`/permissions/groups/${groupId}`,
|
|
72
|
+
'PUT',
|
|
73
|
+
params,
|
|
74
|
+
);
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Delete a permission group
|
|
80
|
+
* @param {string} groupId - Group ID to delete
|
|
81
|
+
* @returns {Promise<Object>} Deletion confirmation
|
|
82
|
+
* @example
|
|
83
|
+
* await sdk.permissions.deleteGroup('group-123');
|
|
84
|
+
*/
|
|
85
|
+
async deleteGroup(groupId) {
|
|
86
|
+
groupId = String(groupId);
|
|
87
|
+
this.sdk.validateParams(
|
|
88
|
+
{ groupId },
|
|
89
|
+
{
|
|
90
|
+
groupId: { type: 'string', required: true },
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const result = await this.sdk._fetch(
|
|
95
|
+
`/permissions/groups/${groupId}`,
|
|
96
|
+
'DELETE',
|
|
97
|
+
);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Add a user to a permission group
|
|
103
|
+
* @param {string} groupId - Group ID
|
|
104
|
+
* @param {string} userId - User ID to add
|
|
105
|
+
* @returns {Promise<Object>} Membership confirmation
|
|
106
|
+
* @example
|
|
107
|
+
* await sdk.permissions.addGroupMember('group-123', 'user-456');
|
|
108
|
+
*/
|
|
109
|
+
async addGroupMember(groupId, userId) {
|
|
110
|
+
groupId = String(groupId);
|
|
111
|
+
userId = String(userId);
|
|
112
|
+
this.sdk.validateParams(
|
|
113
|
+
{ groupId, userId },
|
|
114
|
+
{
|
|
115
|
+
groupId: { type: 'string', required: true },
|
|
116
|
+
userId: { type: 'string', required: true },
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const params = {
|
|
121
|
+
body: { userId },
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const result = await this.sdk._fetch(
|
|
125
|
+
`/permissions/groups/${groupId}/members`,
|
|
126
|
+
'POST',
|
|
127
|
+
params,
|
|
128
|
+
);
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Remove a user from a permission group
|
|
134
|
+
* @param {string} groupId - Group ID
|
|
135
|
+
* @param {string} userId - User ID to remove
|
|
136
|
+
* @returns {Promise<Object>} Removal confirmation
|
|
137
|
+
* @example
|
|
138
|
+
* await sdk.permissions.removeGroupMember('group-123', 'user-456');
|
|
139
|
+
*/
|
|
140
|
+
async removeGroupMember(groupId, userId) {
|
|
141
|
+
groupId = String(groupId);
|
|
142
|
+
userId = String(userId);
|
|
143
|
+
this.sdk.validateParams(
|
|
144
|
+
{ groupId, userId },
|
|
145
|
+
{
|
|
146
|
+
groupId: { type: 'string', required: true },
|
|
147
|
+
userId: { type: 'string', required: true },
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const result = await this.sdk._fetch(
|
|
152
|
+
`/permissions/groups/${groupId}/members/${userId}`,
|
|
153
|
+
'DELETE',
|
|
154
|
+
);
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* List permission sets (system defaults are returned first)
|
|
160
|
+
* @returns {Promise<Object>} Object with results: Array of permission sets
|
|
161
|
+
* @example
|
|
162
|
+
* const { results } = await sdk.permissions.listPermissionSets();
|
|
163
|
+
*/
|
|
164
|
+
async listPermissionSets() {
|
|
165
|
+
const result = await this.sdk._fetch('/permissions/sets', 'GET');
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create a new permission set
|
|
171
|
+
* @param {Object} set - Permission set configuration
|
|
172
|
+
* @param {string} set.name - Permission set name (required)
|
|
173
|
+
* @param {Array<string>} set.scopes - Scopes granted by this set (required)
|
|
174
|
+
* @returns {Promise<Object>} Created permission set
|
|
175
|
+
* @example
|
|
176
|
+
* await sdk.permissions.createPermissionSet({
|
|
177
|
+
* name: 'Voice Admin',
|
|
178
|
+
* scopes: ['voice:calls:read', 'voice:calls:write'],
|
|
179
|
+
* });
|
|
180
|
+
*/
|
|
181
|
+
async createPermissionSet({ name, scopes }) {
|
|
182
|
+
this.sdk.validateParams(
|
|
183
|
+
{ name, scopes },
|
|
184
|
+
{
|
|
185
|
+
name: { type: 'string', required: true },
|
|
186
|
+
scopes: { type: 'array', required: true },
|
|
187
|
+
},
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const params = {
|
|
191
|
+
body: { name, scopes },
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const result = await this.sdk._fetch('/permissions/sets', 'POST', params);
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Update an existing permission set
|
|
200
|
+
* @param {string} setId - Permission set ID to update
|
|
201
|
+
* @param {Object} data - Fields to update (e.g. name, scopes)
|
|
202
|
+
* @returns {Promise<Object>} Updated permission set
|
|
203
|
+
* @example
|
|
204
|
+
* await sdk.permissions.updatePermissionSet('set-123', { scopes: ['voice:calls:read'] });
|
|
205
|
+
*/
|
|
206
|
+
async updatePermissionSet(setId, data) {
|
|
207
|
+
setId = String(setId);
|
|
208
|
+
this.sdk.validateParams(
|
|
209
|
+
{ setId },
|
|
210
|
+
{
|
|
211
|
+
setId: { type: 'string', required: true },
|
|
212
|
+
},
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const params = {
|
|
216
|
+
body: data,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const result = await this.sdk._fetch(
|
|
220
|
+
`/permissions/sets/${setId}`,
|
|
221
|
+
'PUT',
|
|
222
|
+
params,
|
|
223
|
+
);
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Delete a permission set
|
|
229
|
+
* @param {string} setId - Permission set ID to delete
|
|
230
|
+
* @returns {Promise<Object>} Deletion confirmation
|
|
231
|
+
* @example
|
|
232
|
+
* await sdk.permissions.deletePermissionSet('set-123');
|
|
233
|
+
*/
|
|
234
|
+
async deletePermissionSet(setId) {
|
|
235
|
+
setId = String(setId);
|
|
236
|
+
this.sdk.validateParams(
|
|
237
|
+
{ setId },
|
|
238
|
+
{
|
|
239
|
+
setId: { type: 'string', required: true },
|
|
240
|
+
},
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const result = await this.sdk._fetch(
|
|
244
|
+
`/permissions/sets/${setId}`,
|
|
245
|
+
'DELETE',
|
|
246
|
+
);
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Assign a permission set to a principal (user or group)
|
|
252
|
+
* @param {Object} assignment - Assignment configuration
|
|
253
|
+
* @param {string} assignment.permissionSetId - Permission set ID (required)
|
|
254
|
+
* @param {string} assignment.principalType - Principal type, e.g. 'user' or 'group' (required)
|
|
255
|
+
* @param {string} assignment.principalId - Principal ID (required)
|
|
256
|
+
* @param {string} assignment.grantType - Grant type, e.g. 'allow' or 'deny' (required)
|
|
257
|
+
* @returns {Promise<Object>} Created assignment
|
|
258
|
+
* @example
|
|
259
|
+
* await sdk.permissions.assignPermissionSet({
|
|
260
|
+
* permissionSetId: 'set-123',
|
|
261
|
+
* principalType: 'user',
|
|
262
|
+
* principalId: 'user-456',
|
|
263
|
+
* grantType: 'allow',
|
|
264
|
+
* });
|
|
265
|
+
*/
|
|
266
|
+
async assignPermissionSet({
|
|
267
|
+
permissionSetId,
|
|
268
|
+
principalType,
|
|
269
|
+
principalId,
|
|
270
|
+
grantType,
|
|
271
|
+
}) {
|
|
272
|
+
permissionSetId = String(permissionSetId);
|
|
273
|
+
principalId = String(principalId);
|
|
274
|
+
this.sdk.validateParams(
|
|
275
|
+
{ permissionSetId, principalType, principalId, grantType },
|
|
276
|
+
{
|
|
277
|
+
permissionSetId: { type: 'string', required: true },
|
|
278
|
+
principalType: { type: 'string', required: true },
|
|
279
|
+
principalId: { type: 'string', required: true },
|
|
280
|
+
grantType: { type: 'string', required: true },
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const params = {
|
|
285
|
+
body: { permissionSetId, principalType, principalId, grantType },
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const result = await this.sdk._fetch(
|
|
289
|
+
'/permissions/assignments',
|
|
290
|
+
'POST',
|
|
291
|
+
params,
|
|
292
|
+
);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Remove a permission set assignment from a principal
|
|
298
|
+
* @param {string} permissionSetId - Permission set ID
|
|
299
|
+
* @param {string} principalType - Principal type, e.g. 'user' or 'group'
|
|
300
|
+
* @param {string} principalId - Principal ID
|
|
301
|
+
* @returns {Promise<Object>} Removal confirmation
|
|
302
|
+
* @example
|
|
303
|
+
* await sdk.permissions.unassignPermissionSet('set-123', 'user', 'user-456');
|
|
304
|
+
*/
|
|
305
|
+
async unassignPermissionSet(permissionSetId, principalType, principalId) {
|
|
306
|
+
permissionSetId = String(permissionSetId);
|
|
307
|
+
principalId = String(principalId);
|
|
308
|
+
this.sdk.validateParams(
|
|
309
|
+
{ permissionSetId, principalType, principalId },
|
|
310
|
+
{
|
|
311
|
+
permissionSetId: { type: 'string', required: true },
|
|
312
|
+
principalType: { type: 'string', required: true },
|
|
313
|
+
principalId: { type: 'string', required: true },
|
|
314
|
+
},
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const result = await this.sdk._fetch(
|
|
318
|
+
`/permissions/assignments/${permissionSetId}/${principalType}/${principalId}`,
|
|
319
|
+
'DELETE',
|
|
320
|
+
);
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get a user's effective scopes, resolved from all assigned permission sets
|
|
326
|
+
* @param {string} userId - User ID
|
|
327
|
+
* @returns {Promise<Object>} Object with userId, scopes, breakdown ({scope, sources}[]), deniedScopes
|
|
328
|
+
* @example
|
|
329
|
+
* const { scopes, breakdown, deniedScopes } = await sdk.permissions.getEffectiveScopes('user-456');
|
|
330
|
+
*/
|
|
331
|
+
/**
|
|
332
|
+
* Effective scopes contributed by membership in a group.
|
|
333
|
+
* @param {string|number} groupId - Group ID (required)
|
|
334
|
+
* @returns {Promise<Object>} { groupId, scopes, breakdown, deniedScopes }
|
|
335
|
+
*/
|
|
336
|
+
async getGroupEffectiveScopes(groupId) {
|
|
337
|
+
groupId = String(groupId);
|
|
338
|
+
this.sdk.validateParams(
|
|
339
|
+
{ groupId },
|
|
340
|
+
{
|
|
341
|
+
groupId: { type: 'string', required: true },
|
|
342
|
+
},
|
|
343
|
+
);
|
|
344
|
+
const result = await this.sdk._fetch(
|
|
345
|
+
`/permissions/groups/${groupId}/effective-scopes`,
|
|
346
|
+
'GET',
|
|
347
|
+
);
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async getEffectiveScopes(userId) {
|
|
352
|
+
userId = String(userId);
|
|
353
|
+
this.sdk.validateParams(
|
|
354
|
+
{ userId },
|
|
355
|
+
{
|
|
356
|
+
userId: { type: 'string', required: true },
|
|
357
|
+
},
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const result = await this.sdk._fetch(
|
|
361
|
+
`/permissions/users/${userId}/effective-scopes`,
|
|
362
|
+
'GET',
|
|
363
|
+
);
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Get the full catalog of available scopes, grouped by pillar
|
|
369
|
+
* @returns {Promise<Object>} Object with pillars: Array of {pillar, scopes: [{scope, label}]}
|
|
370
|
+
* @example
|
|
371
|
+
* const { pillars } = await sdk.permissions.getScopeCatalog();
|
|
372
|
+
*/
|
|
373
|
+
async getScopeCatalog() {
|
|
374
|
+
const result = await this.sdk._fetch('/permissions/scope-catalog', 'GET');
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
}
|