@mondaydotcomorg/monday-authorization 3.5.0-feat-use-profile-for-graph-can-action-in-scope-f1451ab → 3.5.0-feat-shaime-support-entity-attributes-in-authorization-sdk-c9e4cfc
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/dist/attributions-service.d.ts.map +1 -1
- package/dist/attributions-service.js +1 -0
- package/dist/authorization-attributes-ms-service.d.ts +37 -0
- package/dist/authorization-attributes-ms-service.d.ts.map +1 -0
- package/dist/authorization-attributes-ms-service.js +232 -0
- package/dist/authorization-attributes-service.d.ts +45 -1
- package/dist/authorization-attributes-service.d.ts.map +1 -1
- package/dist/authorization-attributes-service.js +262 -0
- package/dist/clients/graph-api.d.ts.map +1 -1
- package/dist/clients/graph-api.js +0 -1
- package/dist/constants.d.ts +0 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -4
- package/dist/errors/argument-error.d.ts +4 -0
- package/dist/errors/argument-error.d.ts.map +1 -0
- package/dist/errors/argument-error.js +11 -0
- package/dist/esm/attributions-service.d.ts.map +1 -1
- package/dist/esm/attributions-service.mjs +1 -0
- package/dist/esm/authorization-attributes-ms-service.d.ts +37 -0
- package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -0
- package/dist/esm/authorization-attributes-ms-service.mjs +230 -0
- package/dist/esm/authorization-attributes-service.d.ts +45 -1
- package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
- package/dist/esm/authorization-attributes-service.mjs +263 -1
- package/dist/esm/clients/graph-api.d.ts.map +1 -1
- package/dist/esm/clients/graph-api.mjs +1 -2
- package/dist/esm/constants.d.ts +0 -3
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +1 -5
- package/dist/esm/errors/argument-error.d.ts +4 -0
- package/dist/esm/errors/argument-error.d.ts.map +1 -0
- package/dist/esm/errors/argument-error.mjs +9 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +4 -0
- package/dist/esm/resource-attribute-assignment.d.ts +25 -0
- package/dist/esm/resource-attribute-assignment.d.ts.map +1 -0
- package/dist/esm/resource-attribute-assignment.mjs +60 -0
- package/dist/esm/resource-attributes-constants.d.ts +25 -0
- package/dist/esm/resource-attributes-constants.d.ts.map +1 -0
- package/dist/esm/resource-attributes-constants.mjs +25 -0
- package/dist/esm/types/authorization-attributes-contracts.d.ts +19 -3
- package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/resource-attribute-assignment.d.ts +25 -0
- package/dist/resource-attribute-assignment.d.ts.map +1 -0
- package/dist/resource-attribute-assignment.js +62 -0
- package/dist/resource-attributes-constants.d.ts +25 -0
- package/dist/resource-attributes-constants.d.ts.map +1 -0
- package/dist/resource-attributes-constants.js +28 -0
- package/dist/types/authorization-attributes-contracts.d.ts +19 -3
- package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/attributions-service.ts +4 -0
- package/src/authorization-attributes-ms-service.ts +327 -0
- package/src/authorization-attributes-service.ts +325 -0
- package/src/clients/graph-api.ts +1 -2
- package/src/constants.ts +0 -4
- package/src/errors/argument-error.ts +8 -0
- package/src/index.ts +16 -0
- package/src/resource-attribute-assignment.ts +70 -0
- package/src/resource-attributes-constants.ts +27 -0
- package/src/types/authorization-attributes-contracts.ts +49 -3
|
@@ -6,7 +6,14 @@ import {
|
|
|
6
6
|
ResourceAttributeAssignment,
|
|
7
7
|
ResourceAttributeResponse,
|
|
8
8
|
ResourceAttributesOperation,
|
|
9
|
+
EntityAttributeAssignment,
|
|
10
|
+
EntityAttributeResponse,
|
|
11
|
+
ResourceType,
|
|
12
|
+
EntityType,
|
|
13
|
+
ResourceAttributeKeyType,
|
|
14
|
+
EntityAttributeKeyType,
|
|
9
15
|
} from './types/authorization-attributes-contracts';
|
|
16
|
+
import { AuthorizationInternalService } from './authorization-internal-service';
|
|
10
17
|
import { Resource } from './types/general';
|
|
11
18
|
import { logger } from './authorization-internal-service';
|
|
12
19
|
import { getAttributionsFromApi } from './attributions-service';
|
|
@@ -24,6 +31,8 @@ export class AuthorizationAttributesService {
|
|
|
24
31
|
private static API_PATHS = {
|
|
25
32
|
UPSERT_RESOURCE_ATTRIBUTES: '/attributes/{accountId}/resource',
|
|
26
33
|
DELETE_RESOURCE_ATTRIBUTES: '/attributes/{accountId}/resource/{resourceType}/{resourceId}',
|
|
34
|
+
UPSERT_ENTITY_ATTRIBUTES: '/attributes/{accountId}/entity',
|
|
35
|
+
DELETE_ENTITY_ATTRIBUTES: '/attributes/{accountId}/entity/{entityType}/{entityId}',
|
|
27
36
|
} as const;
|
|
28
37
|
private httpClient: HttpClient;
|
|
29
38
|
private fetchOptions: RecursivePartial<FetcherConfig>;
|
|
@@ -231,4 +240,320 @@ export class AuthorizationAttributesService {
|
|
|
231
240
|
return false;
|
|
232
241
|
}
|
|
233
242
|
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Validates resource attribute assignments array
|
|
246
|
+
*/
|
|
247
|
+
private static validateResourceAttributeAssignments(
|
|
248
|
+
assignments: ResourceAttributeAssignment[]
|
|
249
|
+
): void {
|
|
250
|
+
if (!Array.isArray(assignments)) {
|
|
251
|
+
throw new Error('resourceAttributeAssignments must be an array');
|
|
252
|
+
}
|
|
253
|
+
if (assignments.length === 0) {
|
|
254
|
+
throw new Error('resourceAttributeAssignments must contain at least 1 item');
|
|
255
|
+
}
|
|
256
|
+
if (assignments.length > 100) {
|
|
257
|
+
throw new Error('resourceAttributeAssignments must contain at most 100 items');
|
|
258
|
+
}
|
|
259
|
+
for (let i = 0; i < assignments.length; i++) {
|
|
260
|
+
const assignment = assignments[i];
|
|
261
|
+
if (!assignment.resourceId || typeof assignment.resourceId !== 'number') {
|
|
262
|
+
throw new Error(`resourceAttributeAssignments[${i}].resourceId is required and must be a number`);
|
|
263
|
+
}
|
|
264
|
+
if (!assignment.resourceType || typeof assignment.resourceType !== 'string') {
|
|
265
|
+
throw new Error(`resourceAttributeAssignments[${i}].resourceType is required and must be a string`);
|
|
266
|
+
}
|
|
267
|
+
if (!assignment.key || typeof assignment.key !== 'string') {
|
|
268
|
+
throw new Error(`resourceAttributeAssignments[${i}].key is required and must be a string`);
|
|
269
|
+
}
|
|
270
|
+
if (assignment.value === undefined || typeof assignment.value !== 'string') {
|
|
271
|
+
throw new Error(`resourceAttributeAssignments[${i}].value is required and must be a string`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Validates entity attribute assignments array
|
|
278
|
+
*/
|
|
279
|
+
private static validateEntityAttributeAssignments(assignments: EntityAttributeAssignment[]): void {
|
|
280
|
+
if (!Array.isArray(assignments)) {
|
|
281
|
+
throw new Error('entityAttributeAssignments must be an array');
|
|
282
|
+
}
|
|
283
|
+
if (assignments.length === 0) {
|
|
284
|
+
throw new Error('entityAttributeAssignments must contain at least 1 item');
|
|
285
|
+
}
|
|
286
|
+
if (assignments.length > 100) {
|
|
287
|
+
throw new Error('entityAttributeAssignments must contain at most 100 items');
|
|
288
|
+
}
|
|
289
|
+
for (let i = 0; i < assignments.length; i++) {
|
|
290
|
+
const assignment = assignments[i];
|
|
291
|
+
if (!assignment.entityId || typeof assignment.entityId !== 'number') {
|
|
292
|
+
throw new Error(`entityAttributeAssignments[${i}].entityId is required and must be a number`);
|
|
293
|
+
}
|
|
294
|
+
if (!assignment.entityType || typeof assignment.entityType !== 'string') {
|
|
295
|
+
throw new Error(`entityAttributeAssignments[${i}].entityType is required and must be a string`);
|
|
296
|
+
}
|
|
297
|
+
if (!assignment.key || typeof assignment.key !== 'string') {
|
|
298
|
+
throw new Error(`entityAttributeAssignments[${i}].key is required and must be a string`);
|
|
299
|
+
}
|
|
300
|
+
if (assignment.value === undefined || typeof assignment.value !== 'string') {
|
|
301
|
+
throw new Error(`entityAttributeAssignments[${i}].value is required and must be a string`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Upsert resource attributes synchronously.
|
|
308
|
+
* Matches API endpoint: POST /attributes/:accountId/resource
|
|
309
|
+
* @param accountId The account ID
|
|
310
|
+
* @param resourceAttributeAssignments Array of ResourceAttributeAssignment objects (1-100 items)
|
|
311
|
+
* @returns Promise with response containing affected attributes
|
|
312
|
+
*/
|
|
313
|
+
static async upsertResourceAttributesSync(
|
|
314
|
+
accountId: number,
|
|
315
|
+
resourceAttributeAssignments: ResourceAttributeAssignment[]
|
|
316
|
+
): Promise<ResourceAttributeResponse> {
|
|
317
|
+
// Validate inputs
|
|
318
|
+
if (!Number.isInteger(accountId)) {
|
|
319
|
+
throw new Error(`accountId must be an integer, got: ${accountId}`);
|
|
320
|
+
}
|
|
321
|
+
AuthorizationAttributesService.validateResourceAttributeAssignments(resourceAttributeAssignments);
|
|
322
|
+
|
|
323
|
+
const httpClient = Api.getPart('httpClient');
|
|
324
|
+
if (!httpClient) {
|
|
325
|
+
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
329
|
+
const path = AuthorizationAttributesService.API_PATHS.UPSERT_RESOURCE_ATTRIBUTES.replace(
|
|
330
|
+
'{accountId}',
|
|
331
|
+
accountId.toString()
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
return await httpClient.fetch<ResourceAttributeResponse>(
|
|
336
|
+
{
|
|
337
|
+
url: {
|
|
338
|
+
appName: APP_NAME,
|
|
339
|
+
path,
|
|
340
|
+
},
|
|
341
|
+
method: 'POST',
|
|
342
|
+
headers: {
|
|
343
|
+
'Content-Type': 'application/json',
|
|
344
|
+
...attributionHeaders,
|
|
345
|
+
},
|
|
346
|
+
body: JSON.stringify({ resourceAttributeAssignments }),
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
350
|
+
retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
} catch (err) {
|
|
354
|
+
if (err instanceof HttpFetcherError) {
|
|
355
|
+
throw new Error(ERROR_MESSAGES.REQUEST_FAILED('upsertResourceAttributesSync', err.status, err.message));
|
|
356
|
+
}
|
|
357
|
+
throw err;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Delete resource attributes synchronously.
|
|
363
|
+
* Matches API endpoint: DELETE /attributes/:accountId/resource/:resourceType/:resourceId
|
|
364
|
+
* @param accountId The account ID
|
|
365
|
+
* @param resourceType The resource type
|
|
366
|
+
* @param resourceId The resource ID
|
|
367
|
+
* @param keys Array of attribute keys to delete
|
|
368
|
+
* @returns Promise with response containing affected attributes
|
|
369
|
+
*/
|
|
370
|
+
static async deleteResourceAttributesSync(
|
|
371
|
+
accountId: number,
|
|
372
|
+
resourceType: ResourceType,
|
|
373
|
+
resourceId: number,
|
|
374
|
+
keys: ResourceAttributeKeyType[]
|
|
375
|
+
): Promise<ResourceAttributeResponse> {
|
|
376
|
+
// Validate inputs
|
|
377
|
+
if (!Number.isInteger(accountId)) {
|
|
378
|
+
throw new Error(`accountId must be an integer, got: ${accountId}`);
|
|
379
|
+
}
|
|
380
|
+
if (!resourceType || typeof resourceType !== 'string') {
|
|
381
|
+
throw new Error(`resourceType must be a string, got: ${typeof resourceType}`);
|
|
382
|
+
}
|
|
383
|
+
if (!Number.isInteger(resourceId)) {
|
|
384
|
+
throw new Error(`resourceId must be an integer, got: ${resourceId}`);
|
|
385
|
+
}
|
|
386
|
+
if (!Array.isArray(keys)) {
|
|
387
|
+
throw new Error('keys must be an array');
|
|
388
|
+
}
|
|
389
|
+
if (keys.length === 0) {
|
|
390
|
+
throw new Error('keys must contain at least 1 item');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const httpClient = Api.getPart('httpClient');
|
|
394
|
+
if (!httpClient) {
|
|
395
|
+
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
399
|
+
const path = AuthorizationAttributesService.API_PATHS.DELETE_RESOURCE_ATTRIBUTES.replace(
|
|
400
|
+
'{accountId}',
|
|
401
|
+
accountId.toString()
|
|
402
|
+
)
|
|
403
|
+
.replace('{resourceType}', resourceType)
|
|
404
|
+
.replace('{resourceId}', resourceId.toString());
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
return await httpClient.fetch<ResourceAttributeResponse>(
|
|
408
|
+
{
|
|
409
|
+
url: {
|
|
410
|
+
appName: APP_NAME,
|
|
411
|
+
path,
|
|
412
|
+
},
|
|
413
|
+
method: 'DELETE',
|
|
414
|
+
headers: {
|
|
415
|
+
'Content-Type': 'application/json',
|
|
416
|
+
...attributionHeaders,
|
|
417
|
+
},
|
|
418
|
+
body: JSON.stringify({ keys }),
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
422
|
+
retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
if (err instanceof HttpFetcherError) {
|
|
427
|
+
throw new Error(ERROR_MESSAGES.REQUEST_FAILED('deleteResourceAttributesSync', err.status, err.message));
|
|
428
|
+
}
|
|
429
|
+
throw err;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Upsert entity attributes synchronously.
|
|
435
|
+
* Matches API endpoint: POST /attributes/:accountId/entity
|
|
436
|
+
* @param accountId The account ID
|
|
437
|
+
* @param entityAttributeAssignments Array of EntityAttributeAssignment objects (1-100 items)
|
|
438
|
+
* @returns Promise with response containing affected attributes
|
|
439
|
+
*/
|
|
440
|
+
static async upsertEntityAttributesSync(
|
|
441
|
+
accountId: number,
|
|
442
|
+
entityAttributeAssignments: EntityAttributeAssignment[]
|
|
443
|
+
): Promise<EntityAttributeResponse> {
|
|
444
|
+
// Validate inputs
|
|
445
|
+
if (!Number.isInteger(accountId)) {
|
|
446
|
+
throw new Error(`accountId must be an integer, got: ${accountId}`);
|
|
447
|
+
}
|
|
448
|
+
AuthorizationAttributesService.validateEntityAttributeAssignments(entityAttributeAssignments);
|
|
449
|
+
|
|
450
|
+
const httpClient = Api.getPart('httpClient');
|
|
451
|
+
if (!httpClient) {
|
|
452
|
+
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
456
|
+
const path = AuthorizationAttributesService.API_PATHS.UPSERT_ENTITY_ATTRIBUTES.replace(
|
|
457
|
+
'{accountId}',
|
|
458
|
+
accountId.toString()
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
try {
|
|
462
|
+
return await httpClient.fetch<EntityAttributeResponse>(
|
|
463
|
+
{
|
|
464
|
+
url: {
|
|
465
|
+
appName: APP_NAME,
|
|
466
|
+
path,
|
|
467
|
+
},
|
|
468
|
+
method: 'POST',
|
|
469
|
+
headers: {
|
|
470
|
+
'Content-Type': 'application/json',
|
|
471
|
+
...attributionHeaders,
|
|
472
|
+
},
|
|
473
|
+
body: JSON.stringify({ entityAttributeAssignments }),
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
477
|
+
retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
} catch (err) {
|
|
481
|
+
if (err instanceof HttpFetcherError) {
|
|
482
|
+
throw new Error(ERROR_MESSAGES.REQUEST_FAILED('upsertEntityAttributesSync', err.status, err.message));
|
|
483
|
+
}
|
|
484
|
+
throw err;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Delete entity attributes synchronously.
|
|
490
|
+
* Matches API endpoint: DELETE /attributes/:accountId/entity/:entityType/:entityId
|
|
491
|
+
* @param accountId The account ID
|
|
492
|
+
* @param entityType The entity type
|
|
493
|
+
* @param entityId The entity ID
|
|
494
|
+
* @param keys Array of attribute keys to delete
|
|
495
|
+
* @returns Promise with response containing affected attributes
|
|
496
|
+
*/
|
|
497
|
+
static async deleteEntityAttributesSync(
|
|
498
|
+
accountId: number,
|
|
499
|
+
entityType: EntityType,
|
|
500
|
+
entityId: number,
|
|
501
|
+
keys: EntityAttributeKeyType[]
|
|
502
|
+
): Promise<EntityAttributeResponse> {
|
|
503
|
+
// Validate inputs
|
|
504
|
+
if (!Number.isInteger(accountId)) {
|
|
505
|
+
throw new Error(`accountId must be an integer, got: ${accountId}`);
|
|
506
|
+
}
|
|
507
|
+
if (!entityType || typeof entityType !== 'string') {
|
|
508
|
+
throw new Error(`entityType must be a string, got: ${typeof entityType}`);
|
|
509
|
+
}
|
|
510
|
+
if (!Number.isInteger(entityId)) {
|
|
511
|
+
throw new Error(`entityId must be an integer, got: ${entityId}`);
|
|
512
|
+
}
|
|
513
|
+
if (!Array.isArray(keys)) {
|
|
514
|
+
throw new Error('keys must be an array');
|
|
515
|
+
}
|
|
516
|
+
if (keys.length === 0) {
|
|
517
|
+
throw new Error('keys must contain at least 1 item');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const httpClient = Api.getPart('httpClient');
|
|
521
|
+
if (!httpClient) {
|
|
522
|
+
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
526
|
+
const path = AuthorizationAttributesService.API_PATHS.DELETE_ENTITY_ATTRIBUTES.replace(
|
|
527
|
+
'{accountId}',
|
|
528
|
+
accountId.toString()
|
|
529
|
+
)
|
|
530
|
+
.replace('{entityType}', entityType)
|
|
531
|
+
.replace('{entityId}', entityId.toString());
|
|
532
|
+
|
|
533
|
+
try {
|
|
534
|
+
return await httpClient.fetch<EntityAttributeResponse>(
|
|
535
|
+
{
|
|
536
|
+
url: {
|
|
537
|
+
appName: APP_NAME,
|
|
538
|
+
path,
|
|
539
|
+
},
|
|
540
|
+
method: 'DELETE',
|
|
541
|
+
headers: {
|
|
542
|
+
'Content-Type': 'application/json',
|
|
543
|
+
...attributionHeaders,
|
|
544
|
+
},
|
|
545
|
+
body: JSON.stringify({ keys }),
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
timeout: AuthorizationInternalService.getRequestTimeout(),
|
|
549
|
+
retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
} catch (err) {
|
|
553
|
+
if (err instanceof HttpFetcherError) {
|
|
554
|
+
throw new Error(ERROR_MESSAGES.REQUEST_FAILED('deleteEntityAttributesSync', err.status, err.message));
|
|
555
|
+
}
|
|
556
|
+
throw err;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
234
559
|
}
|
package/src/clients/graph-api.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
GraphPermissionReason,
|
|
19
19
|
} from '../types/graph-api.types';
|
|
20
20
|
import { scopeToResource } from '../utils/authorization.utils';
|
|
21
|
-
import { GRAPH_APP_NAME
|
|
21
|
+
import { GRAPH_APP_NAME } from '../constants';
|
|
22
22
|
import { handleApiError } from '../utils/api-error-handler';
|
|
23
23
|
|
|
24
24
|
const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
|
|
@@ -85,7 +85,6 @@ export class GraphApi {
|
|
|
85
85
|
url: {
|
|
86
86
|
appName: GRAPH_APP_NAME,
|
|
87
87
|
path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
|
|
88
|
-
profile: GraphProfile.PERMISSION,
|
|
89
88
|
},
|
|
90
89
|
method: 'POST',
|
|
91
90
|
headers: {
|
package/src/constants.ts
CHANGED
|
@@ -4,10 +4,6 @@ import { FetcherConfig } from '@mondaydotcomorg/trident-backend-api';
|
|
|
4
4
|
export const APP_NAME = 'authorization';
|
|
5
5
|
export const GRAPH_APP_NAME = 'authorization-graph';
|
|
6
6
|
|
|
7
|
-
export enum GraphProfile {
|
|
8
|
-
PERMISSION = 'authorization-graph-permission',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
7
|
export const ERROR_MESSAGES = {
|
|
12
8
|
HTTP_CLIENT_NOT_INITIALIZED: 'MondayAuthorization: HTTP client is not initialized',
|
|
13
9
|
REQUEST_FAILED: (method: string, status: number, reason: string) =>
|
package/src/index.ts
CHANGED
|
@@ -58,6 +58,22 @@ export {
|
|
|
58
58
|
} from './authorization-middleware';
|
|
59
59
|
export { AuthorizationService, AuthorizeResponse } from './authorization-service';
|
|
60
60
|
export { AuthorizationAttributesService } from './authorization-attributes-service';
|
|
61
|
+
export { AuthorizationAttributesMsService } from './authorization-attributes-ms-service';
|
|
62
|
+
export { ResourceAttributeAssignment } from './resource-attribute-assignment';
|
|
63
|
+
export { RESOURCE_TYPES, RESOURCE_ATTRIBUTES_CONSTANTS } from './resource-attributes-constants';
|
|
64
|
+
export { ArgumentError } from './errors/argument-error';
|
|
65
|
+
export {
|
|
66
|
+
EntityAttributeAssignment,
|
|
67
|
+
ResourceAttributeResponse,
|
|
68
|
+
EntityAttributeResponse,
|
|
69
|
+
ResourceType,
|
|
70
|
+
EntityType,
|
|
71
|
+
ResourceAttributeKeyType,
|
|
72
|
+
EntityAttributeKeyType,
|
|
73
|
+
CommonAttributeKey,
|
|
74
|
+
ResourceAttributeKey,
|
|
75
|
+
EntityAttributeKey,
|
|
76
|
+
} from './types/authorization-attributes-contracts';
|
|
61
77
|
export { RolesService } from './roles-service';
|
|
62
78
|
export { MembershipsService } from './memberships';
|
|
63
79
|
export { AuthorizationObject, Resource, BaseRequest, ResourceGetter, ContextGetter } from './types/general';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { RESOURCE_TYPES, ResourceType } from './resource-attributes-constants';
|
|
2
|
+
import { ArgumentError } from './errors/argument-error';
|
|
3
|
+
|
|
4
|
+
export class ResourceAttributeAssignment {
|
|
5
|
+
public readonly resourceId: number;
|
|
6
|
+
public readonly resourceType: ResourceType;
|
|
7
|
+
public readonly attributeKey: string;
|
|
8
|
+
public readonly attributeValue: string;
|
|
9
|
+
|
|
10
|
+
constructor(resourceId: number, resourceType: string, attributeKey: string, attributeValue: string) {
|
|
11
|
+
// Validate resourceId
|
|
12
|
+
if (!Number.isInteger(resourceId)) {
|
|
13
|
+
throw new ArgumentError(`resourceId must be an integer, got: ${resourceId}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Validate resourceType
|
|
17
|
+
const validResourceTypes = Object.values(RESOURCE_TYPES);
|
|
18
|
+
if (!validResourceTypes.includes(resourceType as ResourceType)) {
|
|
19
|
+
throw new ArgumentError(
|
|
20
|
+
`resourceType must be one of [${validResourceTypes.join(', ')}], got: ${resourceType}`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate attributeKey
|
|
25
|
+
if (typeof attributeKey !== 'string') {
|
|
26
|
+
throw new ArgumentError(`attributeKey must be a string, got: ${typeof attributeKey}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Validate attributeValue
|
|
30
|
+
if (typeof attributeValue !== 'string') {
|
|
31
|
+
throw new ArgumentError(`attributeValue must be a string, got: ${typeof attributeValue}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.resourceId = resourceId;
|
|
35
|
+
this.resourceType = resourceType as ResourceType;
|
|
36
|
+
this.attributeKey = attributeKey;
|
|
37
|
+
this.attributeValue = attributeValue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Converts the assignment to hash format with camelCase keys
|
|
42
|
+
* @returns Object with camelCase keys: { resourceId, resourceType, key, value }
|
|
43
|
+
*/
|
|
44
|
+
toH(): { resourceId: number; resourceType: string; key: string; value: string } {
|
|
45
|
+
return {
|
|
46
|
+
resourceId: this.resourceId,
|
|
47
|
+
resourceType: this.resourceType,
|
|
48
|
+
key: this.attributeKey,
|
|
49
|
+
value: this.attributeValue,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Compares two assignments for equality
|
|
55
|
+
* @param other Another ResourceAttributeAssignment instance
|
|
56
|
+
* @returns true if all properties are equal
|
|
57
|
+
*/
|
|
58
|
+
equals(other: ResourceAttributeAssignment): boolean {
|
|
59
|
+
if (!(other instanceof ResourceAttributeAssignment)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return (
|
|
63
|
+
this.resourceId === other.resourceId &&
|
|
64
|
+
this.resourceType === other.resourceType &&
|
|
65
|
+
this.attributeKey === other.attributeKey &&
|
|
66
|
+
this.attributeValue === other.attributeValue
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const RESOURCE_TYPES = {
|
|
2
|
+
ACCOUNT: 'account',
|
|
3
|
+
ACCOUNT_PRODUCT: 'account_product',
|
|
4
|
+
WORKSPACE: 'workspace',
|
|
5
|
+
BOARD: 'board',
|
|
6
|
+
ITEM: 'item',
|
|
7
|
+
TEAM: 'team',
|
|
8
|
+
OVERVIEW: 'overview',
|
|
9
|
+
DOCUMENT: 'document',
|
|
10
|
+
CRM: 'crm',
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export const RESOURCE_ATTRIBUTES_CONSTANTS = {
|
|
14
|
+
ACCOUNT_RESOURCE_ATTRIBUTES: {
|
|
15
|
+
ENABLE_MEMBERS_INVITE_FROM_NON_AUTH_DOMAIN: 'enable_members_invite_from_non_auth_domain',
|
|
16
|
+
},
|
|
17
|
+
WORKSPACE_RESOURCE_ATTRIBUTES: {
|
|
18
|
+
IS_DEFAULT_WORKSPACE: 'is_default_workspace',
|
|
19
|
+
},
|
|
20
|
+
BOARD_RESOURCE_ATTRIBUTES: {
|
|
21
|
+
IS_SYNCABLE_CHILD_ENTITY: 'is_syncable_child_entity',
|
|
22
|
+
SYSTEM_ENTITY_TYPE: 'system_entity_type',
|
|
23
|
+
},
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
export type ResourceType = typeof RESOURCE_TYPES[keyof typeof RESOURCE_TYPES];
|
|
27
|
+
|
|
@@ -1,16 +1,62 @@
|
|
|
1
1
|
import { Resource } from './general';
|
|
2
2
|
|
|
3
|
+
// Resource Types - matching the API
|
|
4
|
+
export type ResourceType =
|
|
5
|
+
| 'account'
|
|
6
|
+
| 'account_product'
|
|
7
|
+
| 'workspace'
|
|
8
|
+
| 'board'
|
|
9
|
+
| 'item'
|
|
10
|
+
| 'team'
|
|
11
|
+
| 'overview'
|
|
12
|
+
| 'document'
|
|
13
|
+
| 'crm';
|
|
14
|
+
|
|
15
|
+
// Entity Types - matching the API
|
|
16
|
+
export type EntityType =
|
|
17
|
+
| 'user'
|
|
18
|
+
| 'team'
|
|
19
|
+
| 'account';
|
|
20
|
+
|
|
21
|
+
// Common attribute keys that can be used for both resources and entities
|
|
22
|
+
export type CommonAttributeKey = string;
|
|
23
|
+
|
|
24
|
+
// Resource-specific attribute keys
|
|
25
|
+
export type ResourceAttributeKey = string;
|
|
26
|
+
|
|
27
|
+
// Entity-specific attribute keys
|
|
28
|
+
export type EntityAttributeKey = string;
|
|
29
|
+
|
|
30
|
+
// Combined types for attribute keys
|
|
31
|
+
export type ResourceAttributeKeyType = CommonAttributeKey | ResourceAttributeKey;
|
|
32
|
+
export type EntityAttributeKeyType = CommonAttributeKey | EntityAttributeKey;
|
|
33
|
+
|
|
34
|
+
// Resource Attribute Assignment - matching API contract
|
|
3
35
|
export interface ResourceAttributeAssignment {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
key:
|
|
36
|
+
resourceId: number;
|
|
37
|
+
resourceType: ResourceType;
|
|
38
|
+
key: ResourceAttributeKeyType;
|
|
7
39
|
value: string;
|
|
8
40
|
}
|
|
9
41
|
|
|
42
|
+
// Entity Attribute Assignment - matching API contract
|
|
43
|
+
export interface EntityAttributeAssignment {
|
|
44
|
+
entityId: number;
|
|
45
|
+
entityType: EntityType;
|
|
46
|
+
key: EntityAttributeKeyType;
|
|
47
|
+
value: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Response types
|
|
10
51
|
export interface ResourceAttributeResponse {
|
|
11
52
|
attributes: ResourceAttributeAssignment[];
|
|
12
53
|
}
|
|
13
54
|
|
|
55
|
+
export interface EntityAttributeResponse {
|
|
56
|
+
attributes: EntityAttributeAssignment[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Legacy types for backward compatibility
|
|
14
60
|
export interface ResourceAttributeDelete {
|
|
15
61
|
resourceType: Resource['type'];
|
|
16
62
|
resourceId: Resource['id'];
|