@mondaydotcomorg/monday-authorization 3.5.0-feat-shaime-support-entity-attributes-in-authorization-sdk-c9e4cfc → 3.5.0-feat-shaime-support-entity-attributes-in-authorization-sdk-8d846f1
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/authorization-attributes-ms-service.d.ts +17 -0
- package/dist/authorization-attributes-ms-service.d.ts.map +1 -1
- package/dist/authorization-attributes-ms-service.js +166 -1
- package/dist/authorization-attributes-service.d.ts +52 -66
- package/dist/authorization-attributes-service.d.ts.map +1 -1
- package/dist/authorization-attributes-service.js +105 -353
- package/dist/constants/sns.d.ts +2 -0
- package/dist/constants/sns.d.ts.map +1 -1
- package/dist/constants/sns.js +4 -0
- package/dist/esm/authorization-attributes-ms-service.d.ts +17 -0
- package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -1
- package/dist/esm/authorization-attributes-ms-service.mjs +166 -1
- package/dist/esm/authorization-attributes-service.d.ts +52 -66
- package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
- package/dist/esm/authorization-attributes-service.mjs +107 -355
- package/dist/esm/constants/sns.d.ts +2 -0
- package/dist/esm/constants/sns.d.ts.map +1 -1
- package/dist/esm/constants/sns.mjs +3 -1
- package/dist/esm/resource-attribute-assignment.d.ts.map +1 -1
- package/dist/esm/resource-attributes-constants.d.ts +1 -1
- package/dist/esm/resource-attributes-constants.d.ts.map +1 -1
- package/dist/esm/types/authorization-attributes-contracts.d.ts +16 -0
- package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/dist/esm/types/authorization-attributes-contracts.mjs +6 -1
- package/dist/resource-attribute-assignment.d.ts.map +1 -1
- package/dist/resource-attributes-constants.d.ts +1 -1
- package/dist/resource-attributes-constants.d.ts.map +1 -1
- package/dist/types/authorization-attributes-contracts.d.ts +16 -0
- package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/dist/types/authorization-attributes-contracts.js +5 -0
- package/package.json +1 -1
- package/src/authorization-attributes-ms-service.ts +258 -17
- package/src/authorization-attributes-service.ts +146 -428
- package/src/constants/sns.ts +2 -0
- package/src/errors/argument-error.ts +1 -2
- package/src/resource-attribute-assignment.ts +1 -4
- package/src/resource-attributes-constants.ts +1 -2
- package/src/types/authorization-attributes-contracts.ts +22 -5
|
@@ -1,151 +1,132 @@
|
|
|
1
1
|
import chunk from 'lodash/chunk.js';
|
|
2
|
-
import { Api, FetcherConfig, HttpClient } from '@mondaydotcomorg/trident-backend-api';
|
|
3
2
|
import { getTopicAttributes, sendToSns } from '@mondaydotcomorg/monday-sns';
|
|
4
|
-
import { HttpFetcherError, RecursivePartial } from '@mondaydotcomorg/monday-fetch-api';
|
|
5
3
|
import {
|
|
6
4
|
ResourceAttributeAssignment,
|
|
7
|
-
ResourceAttributeResponse,
|
|
8
5
|
ResourceAttributesOperation,
|
|
9
6
|
EntityAttributeAssignment,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ResourceAttributeKeyType,
|
|
14
|
-
EntityAttributeKeyType,
|
|
7
|
+
EntityAttributesOperation,
|
|
8
|
+
ResourceAttributeOperationEnum,
|
|
9
|
+
EntityAttributeOperationEnum,
|
|
15
10
|
} from './types/authorization-attributes-contracts';
|
|
16
|
-
import { AuthorizationInternalService } from './authorization-internal-service';
|
|
17
11
|
import { Resource } from './types/general';
|
|
18
12
|
import { logger } from './authorization-internal-service';
|
|
19
|
-
import { getAttributionsFromApi } from './attributions-service';
|
|
20
13
|
import {
|
|
21
14
|
ASYNC_RESOURCE_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE,
|
|
15
|
+
ASYNC_ENTITY_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE,
|
|
22
16
|
RESOURCE_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND,
|
|
17
|
+
ENTITY_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND,
|
|
23
18
|
SNS_ARN_ENV_VAR_NAME,
|
|
24
19
|
SNS_DEV_TEST_NAME,
|
|
25
20
|
} from './constants/sns';
|
|
26
|
-
import { APP_NAME, DEFAULT_FETCH_OPTIONS, ERROR_MESSAGES } from './constants';
|
|
27
21
|
import type { TopicAttributesMap } from 'aws-sdk/clients/sns';
|
|
28
22
|
|
|
29
23
|
export class AuthorizationAttributesService {
|
|
30
24
|
private static LOG_TAG = 'authorization_attributes';
|
|
31
|
-
private static API_PATHS = {
|
|
32
|
-
UPSERT_RESOURCE_ATTRIBUTES: '/attributes/{accountId}/resource',
|
|
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}',
|
|
36
|
-
} as const;
|
|
37
|
-
private httpClient: HttpClient;
|
|
38
|
-
private fetchOptions: RecursivePartial<FetcherConfig>;
|
|
39
25
|
private snsArn: string;
|
|
40
26
|
|
|
41
27
|
/**
|
|
42
28
|
* Public constructor to create the AuthorizationAttributesService instance.
|
|
43
|
-
* @param httpClient The HTTP client to use for API requests, if not provided, the default HTTP client from Api will be used.
|
|
44
|
-
* @param fetchOptions The fetch options to use for API requests, if not provided, the default fetch options will be used.
|
|
45
29
|
*/
|
|
46
|
-
constructor(
|
|
47
|
-
if (!httpClient) {
|
|
48
|
-
httpClient = Api.getPart('httpClient');
|
|
49
|
-
if (!httpClient) {
|
|
50
|
-
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (!fetchOptions) {
|
|
55
|
-
fetchOptions = DEFAULT_FETCH_OPTIONS;
|
|
56
|
-
} else {
|
|
57
|
-
fetchOptions = {
|
|
58
|
-
...DEFAULT_FETCH_OPTIONS,
|
|
59
|
-
...fetchOptions,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
this.httpClient = httpClient;
|
|
63
|
-
this.fetchOptions = fetchOptions;
|
|
30
|
+
constructor() {
|
|
64
31
|
this.snsArn = AuthorizationAttributesService.getSnsTopicArn();
|
|
65
32
|
}
|
|
66
33
|
|
|
67
34
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param
|
|
71
|
-
*
|
|
72
|
-
* @
|
|
35
|
+
* Async function to upsert resource attributes using SNS.
|
|
36
|
+
* Sends the updates request to SNS and returns before the change actually took place.
|
|
37
|
+
* @param accountId The account ID
|
|
38
|
+
* @param appName App name of the calling app
|
|
39
|
+
* @param callerActionIdentifier Action identifier
|
|
40
|
+
* @param resourceAttributeAssignments Array of resource attribute assignments to upsert
|
|
41
|
+
* @return Promise with array of sent operations
|
|
73
42
|
*/
|
|
74
|
-
async
|
|
43
|
+
async upsertResourceAttributesAsync(
|
|
75
44
|
accountId: number,
|
|
45
|
+
appName: string,
|
|
46
|
+
callerActionIdentifier: string,
|
|
76
47
|
resourceAttributeAssignments: ResourceAttributeAssignment[]
|
|
77
|
-
): Promise<
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
appName: APP_NAME,
|
|
84
|
-
path: AuthorizationAttributesService.API_PATHS.UPSERT_RESOURCE_ATTRIBUTES.replace(
|
|
85
|
-
'{accountId}',
|
|
86
|
-
accountId.toString()
|
|
87
|
-
),
|
|
88
|
-
},
|
|
89
|
-
method: 'POST',
|
|
90
|
-
headers: {
|
|
91
|
-
'Content-Type': 'application/json',
|
|
92
|
-
...attributionHeaders,
|
|
93
|
-
},
|
|
94
|
-
body: JSON.stringify({ resourceAttributeAssignments }),
|
|
95
|
-
},
|
|
96
|
-
this.fetchOptions
|
|
97
|
-
);
|
|
98
|
-
} catch (err) {
|
|
99
|
-
if (err instanceof HttpFetcherError) {
|
|
100
|
-
throw new Error(ERROR_MESSAGES.REQUEST_FAILED('upsertResourceAttributes', err.status, err.message));
|
|
101
|
-
}
|
|
102
|
-
throw err;
|
|
103
|
-
}
|
|
48
|
+
): Promise<ResourceAttributesOperation[]> {
|
|
49
|
+
const operations: ResourceAttributesOperation[] = resourceAttributeAssignments.map(assignment => ({
|
|
50
|
+
...assignment,
|
|
51
|
+
operationType: ResourceAttributeOperationEnum.UPSERT,
|
|
52
|
+
}));
|
|
53
|
+
return this.updateResourceAttributesAsync(accountId, appName, callerActionIdentifier, operations);
|
|
104
54
|
}
|
|
105
55
|
|
|
106
56
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* @param
|
|
110
|
-
* @param
|
|
111
|
-
* @
|
|
57
|
+
* Async function to delete resource attributes using SNS.
|
|
58
|
+
* Sends the updates request to SNS and returns before the change actually took place.
|
|
59
|
+
* @param accountId The account ID
|
|
60
|
+
* @param appName App name of the calling app
|
|
61
|
+
* @param callerActionIdentifier Action identifier
|
|
62
|
+
* @param resource The resource (resourceType, resourceId)
|
|
63
|
+
* @param attributeKeys Array of attribute keys to delete
|
|
64
|
+
* @return Promise with array of sent operations
|
|
112
65
|
*/
|
|
113
|
-
async
|
|
66
|
+
async deleteResourceAttributesAsync(
|
|
114
67
|
accountId: number,
|
|
68
|
+
appName: string,
|
|
69
|
+
callerActionIdentifier: string,
|
|
115
70
|
resource: Resource,
|
|
116
71
|
attributeKeys: string[]
|
|
117
|
-
): Promise<
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
72
|
+
): Promise<ResourceAttributesOperation[]> {
|
|
73
|
+
const operations: ResourceAttributesOperation[] = attributeKeys.map(key => ({
|
|
74
|
+
resourceType: resource.type,
|
|
75
|
+
resourceId: resource.id!,
|
|
76
|
+
key,
|
|
77
|
+
operationType: ResourceAttributeOperationEnum.DELETE,
|
|
78
|
+
}));
|
|
79
|
+
return this.updateResourceAttributesAsync(accountId, appName, callerActionIdentifier, operations);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Async function to upsert entity attributes using SNS.
|
|
84
|
+
* Sends the updates request to SNS and returns before the change actually took place.
|
|
85
|
+
* @param accountId The account ID
|
|
86
|
+
* @param appName App name of the calling app
|
|
87
|
+
* @param callerActionIdentifier Action identifier
|
|
88
|
+
* @param entityAttributeAssignments Array of entity attribute assignments to upsert
|
|
89
|
+
* @return Promise with array of sent operations
|
|
90
|
+
*/
|
|
91
|
+
async upsertEntityAttributesAsync(
|
|
92
|
+
accountId: number,
|
|
93
|
+
appName: string,
|
|
94
|
+
callerActionIdentifier: string,
|
|
95
|
+
entityAttributeAssignments: EntityAttributeAssignment[]
|
|
96
|
+
): Promise<EntityAttributesOperation[]> {
|
|
97
|
+
const operations: EntityAttributesOperation[] = entityAttributeAssignments.map(assignment => ({
|
|
98
|
+
...assignment,
|
|
99
|
+
operationType: EntityAttributeOperationEnum.UPSERT,
|
|
100
|
+
}));
|
|
101
|
+
return this.updateEntityAttributesAsync(accountId, appName, callerActionIdentifier, operations);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Async function to delete entity attributes using SNS.
|
|
106
|
+
* Sends the updates request to SNS and returns before the change actually took place.
|
|
107
|
+
* @param accountId The account ID
|
|
108
|
+
* @param appName App name of the calling app
|
|
109
|
+
* @param callerActionIdentifier Action identifier
|
|
110
|
+
* @param entityType The entity type
|
|
111
|
+
* @param entityId The entity ID
|
|
112
|
+
* @param attributeKeys Array of attribute keys to delete
|
|
113
|
+
* @return Promise with array of sent operations
|
|
114
|
+
*/
|
|
115
|
+
async deleteEntityAttributesAsync(
|
|
116
|
+
accountId: number,
|
|
117
|
+
appName: string,
|
|
118
|
+
callerActionIdentifier: string,
|
|
119
|
+
entityType: string,
|
|
120
|
+
entityId: number,
|
|
121
|
+
attributeKeys: string[]
|
|
122
|
+
): Promise<EntityAttributesOperation[]> {
|
|
123
|
+
const operations: EntityAttributesOperation[] = attributeKeys.map(key => ({
|
|
124
|
+
entityType: entityType as any,
|
|
125
|
+
entityId,
|
|
126
|
+
key,
|
|
127
|
+
operationType: EntityAttributeOperationEnum.DELETE,
|
|
128
|
+
}));
|
|
129
|
+
return this.updateEntityAttributesAsync(accountId, appName, callerActionIdentifier, operations);
|
|
149
130
|
}
|
|
150
131
|
|
|
151
132
|
/**
|
|
@@ -167,13 +148,38 @@ export class AuthorizationAttributesService {
|
|
|
167
148
|
const operationChucks = chunk(resourceAttributeOperations, ASYNC_RESOURCE_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE);
|
|
168
149
|
for (const operationsChunk of operationChucks) {
|
|
169
150
|
sendToSnsPromises.push(
|
|
170
|
-
this.
|
|
151
|
+
this.sendSingleResourceSnsMessage(topicArn, accountId, appName, callerActionIdentifier, operationsChunk)
|
|
171
152
|
);
|
|
172
153
|
}
|
|
173
154
|
return (await Promise.all(sendToSnsPromises)).flat();
|
|
174
155
|
}
|
|
175
156
|
|
|
176
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Async function, this function only send the updates request to SNS and return before the change actually took place
|
|
159
|
+
* @param accountId
|
|
160
|
+
* @param appName - App name of the calling app
|
|
161
|
+
* @param callerActionIdentifier - action identifier
|
|
162
|
+
* @param entityAttributeOperations - Array of operations to do on entity attributes.
|
|
163
|
+
* @return {Promise<EntityAttributesOperation[]>} Array of sent operations
|
|
164
|
+
* */
|
|
165
|
+
async updateEntityAttributesAsync(
|
|
166
|
+
accountId: number,
|
|
167
|
+
appName: string,
|
|
168
|
+
callerActionIdentifier: string,
|
|
169
|
+
entityAttributeOperations: EntityAttributesOperation[]
|
|
170
|
+
): Promise<EntityAttributesOperation[]> {
|
|
171
|
+
const topicArn: string = this.snsArn;
|
|
172
|
+
const sendToSnsPromises: Promise<EntityAttributesOperation[]>[] = [];
|
|
173
|
+
const operationChucks = chunk(entityAttributeOperations, ASYNC_ENTITY_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE);
|
|
174
|
+
for (const operationsChunk of operationChucks) {
|
|
175
|
+
sendToSnsPromises.push(
|
|
176
|
+
this.sendSingleEntitySnsMessage(topicArn, accountId, appName, callerActionIdentifier, operationsChunk)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return (await Promise.all(sendToSnsPromises)).flat();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private async sendSingleResourceSnsMessage(
|
|
177
183
|
topicArn: string,
|
|
178
184
|
accountId: number,
|
|
179
185
|
appName: string,
|
|
@@ -201,6 +207,34 @@ export class AuthorizationAttributesService {
|
|
|
201
207
|
}
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
private async sendSingleEntitySnsMessage(
|
|
211
|
+
topicArn: string,
|
|
212
|
+
accountId: number,
|
|
213
|
+
appName: string,
|
|
214
|
+
callerActionIdentifier: string,
|
|
215
|
+
operations: EntityAttributesOperation[]
|
|
216
|
+
): Promise<EntityAttributesOperation[]> {
|
|
217
|
+
const payload = {
|
|
218
|
+
kind: ENTITY_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND,
|
|
219
|
+
payload: {
|
|
220
|
+
accountId: accountId,
|
|
221
|
+
callerAppName: appName,
|
|
222
|
+
callerActionIdentifier: callerActionIdentifier,
|
|
223
|
+
operations: operations,
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
try {
|
|
227
|
+
await sendToSns(payload, topicArn);
|
|
228
|
+
return operations;
|
|
229
|
+
} catch (error) {
|
|
230
|
+
logger.error(
|
|
231
|
+
{ error, tag: AuthorizationAttributesService.LOG_TAG },
|
|
232
|
+
'Authorization entity attributes async update: failed to send operations to SNS'
|
|
233
|
+
);
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
204
238
|
private static getSnsTopicArn(): string {
|
|
205
239
|
const arnFromEnv: string | undefined = process.env[SNS_ARN_ENV_VAR_NAME];
|
|
206
240
|
if (arnFromEnv) {
|
|
@@ -240,320 +274,4 @@ export class AuthorizationAttributesService {
|
|
|
240
274
|
return false;
|
|
241
275
|
}
|
|
242
276
|
}
|
|
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
|
-
}
|
|
559
277
|
}
|
package/src/constants/sns.ts
CHANGED
|
@@ -2,4 +2,6 @@ export const SNS_ARN_ENV_VAR_NAME = 'SHARED_AUTHORIZATION_SNS_ENDPOINT_RESOURCE_
|
|
|
2
2
|
export const SNS_DEV_TEST_NAME =
|
|
3
3
|
'arn:aws:sns:us-east-1:000000000000:monday-authorization-resource-attributes-sns-local';
|
|
4
4
|
export const RESOURCE_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND = 'resourceAttributeModification';
|
|
5
|
+
export const ENTITY_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND = 'entityAttributeModification';
|
|
5
6
|
export const ASYNC_RESOURCE_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE = 100;
|
|
7
|
+
export const ASYNC_ENTITY_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE = 100;
|
|
@@ -16,9 +16,7 @@ export class ResourceAttributeAssignment {
|
|
|
16
16
|
// Validate resourceType
|
|
17
17
|
const validResourceTypes = Object.values(RESOURCE_TYPES);
|
|
18
18
|
if (!validResourceTypes.includes(resourceType as ResourceType)) {
|
|
19
|
-
throw new ArgumentError(
|
|
20
|
-
`resourceType must be one of [${validResourceTypes.join(', ')}], got: ${resourceType}`
|
|
21
|
-
);
|
|
19
|
+
throw new ArgumentError(`resourceType must be one of [${validResourceTypes.join(', ')}], got: ${resourceType}`);
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
// Validate attributeKey
|
|
@@ -67,4 +65,3 @@ export class ResourceAttributeAssignment {
|
|
|
67
65
|
);
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
|
-
|