@mondaydotcomorg/monday-authorization 3.5.1-fix-authorize-profile-picker-7481de0 → 3.5.3-feat-shaime-support-entity-attributes-in-authorization-sdk-e355942

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.
Files changed (126) hide show
  1. package/dist/authorization-attributes-ms-service.d.ts +95 -0
  2. package/dist/authorization-attributes-ms-service.d.ts.map +1 -0
  3. package/dist/authorization-attributes-ms-service.js +362 -0
  4. package/dist/authorization-attributes-service.d.ts +26 -47
  5. package/dist/authorization-attributes-service.d.ts.map +1 -1
  6. package/dist/authorization-attributes-service.js +33 -171
  7. package/dist/authorization-attributes-sns-service.d.ts +91 -0
  8. package/dist/authorization-attributes-sns-service.d.ts.map +1 -0
  9. package/dist/authorization-attributes-sns-service.js +217 -0
  10. package/dist/authorization-middleware.d.ts +2 -2
  11. package/dist/authorization-middleware.d.ts.map +1 -1
  12. package/dist/authorization-service.d.ts +3 -3
  13. package/dist/authorization-service.d.ts.map +1 -1
  14. package/dist/authorization-service.js +7 -34
  15. package/dist/base-attribute-assignment.d.ts +18 -0
  16. package/dist/base-attribute-assignment.d.ts.map +1 -0
  17. package/dist/base-attribute-assignment.js +43 -0
  18. package/dist/constants/sns.d.ts +12 -2
  19. package/dist/constants/sns.d.ts.map +1 -1
  20. package/dist/constants/sns.js +22 -2
  21. package/dist/entity-attribute-assignment.d.ts +14 -0
  22. package/dist/entity-attribute-assignment.d.ts.map +1 -0
  23. package/dist/entity-attribute-assignment.js +24 -0
  24. package/dist/entity-attributes-constants.d.ts +7 -0
  25. package/dist/entity-attributes-constants.d.ts.map +1 -0
  26. package/dist/entity-attributes-constants.js +9 -0
  27. package/dist/errors/argument-error.d.ts +4 -0
  28. package/dist/errors/argument-error.d.ts.map +1 -0
  29. package/dist/errors/argument-error.js +11 -0
  30. package/dist/esm/authorization-attributes-ms-service.d.ts +95 -0
  31. package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -0
  32. package/dist/esm/authorization-attributes-ms-service.mjs +360 -0
  33. package/dist/esm/authorization-attributes-service.d.ts +26 -47
  34. package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
  35. package/dist/esm/authorization-attributes-service.mjs +33 -167
  36. package/dist/esm/authorization-attributes-sns-service.d.ts +91 -0
  37. package/dist/esm/authorization-attributes-sns-service.d.ts.map +1 -0
  38. package/dist/esm/authorization-attributes-sns-service.mjs +211 -0
  39. package/dist/esm/authorization-middleware.d.ts +2 -2
  40. package/dist/esm/authorization-middleware.d.ts.map +1 -1
  41. package/dist/esm/authorization-service.d.ts +3 -3
  42. package/dist/esm/authorization-service.d.ts.map +1 -1
  43. package/dist/esm/authorization-service.mjs +7 -34
  44. package/dist/esm/base-attribute-assignment.d.ts +18 -0
  45. package/dist/esm/base-attribute-assignment.d.ts.map +1 -0
  46. package/dist/esm/base-attribute-assignment.mjs +41 -0
  47. package/dist/esm/constants/sns.d.ts +12 -2
  48. package/dist/esm/constants/sns.d.ts.map +1 -1
  49. package/dist/esm/constants/sns.mjs +17 -3
  50. package/dist/esm/entity-attribute-assignment.d.ts +14 -0
  51. package/dist/esm/entity-attribute-assignment.d.ts.map +1 -0
  52. package/dist/esm/entity-attribute-assignment.mjs +22 -0
  53. package/dist/esm/entity-attributes-constants.d.ts +7 -0
  54. package/dist/esm/entity-attributes-constants.d.ts.map +1 -0
  55. package/dist/esm/entity-attributes-constants.mjs +7 -0
  56. package/dist/esm/errors/argument-error.d.ts +4 -0
  57. package/dist/esm/errors/argument-error.d.ts.map +1 -0
  58. package/dist/esm/errors/argument-error.mjs +9 -0
  59. package/dist/esm/index.d.ts +9 -0
  60. package/dist/esm/index.d.ts.map +1 -1
  61. package/dist/esm/index.mjs +7 -0
  62. package/dist/esm/prometheus-service.d.ts +1 -2
  63. package/dist/esm/prometheus-service.d.ts.map +1 -1
  64. package/dist/esm/resource-attribute-assignment.d.ts +24 -0
  65. package/dist/esm/resource-attribute-assignment.d.ts.map +1 -0
  66. package/dist/esm/resource-attribute-assignment.mjs +34 -0
  67. package/dist/esm/resource-attributes-constants.d.ts +15 -0
  68. package/dist/esm/resource-attributes-constants.d.ts.map +1 -0
  69. package/dist/esm/resource-attributes-constants.mjs +25 -0
  70. package/dist/esm/testKit/index.d.ts +4 -4
  71. package/dist/esm/testKit/index.d.ts.map +1 -1
  72. package/dist/esm/types/authorization-attributes-contracts.d.ts +27 -12
  73. package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
  74. package/dist/esm/types/authorization-attributes-contracts.mjs +6 -6
  75. package/dist/esm/types/authorization-attributes-service.interface.d.ts +57 -0
  76. package/dist/esm/types/authorization-attributes-service.interface.d.ts.map +1 -0
  77. package/dist/esm/types/authorization-attributes-service.interface.mjs +1 -0
  78. package/dist/esm/types/general.d.ts +1 -2
  79. package/dist/esm/types/general.d.ts.map +1 -1
  80. package/dist/esm/utils/validation.d.ts +45 -0
  81. package/dist/esm/utils/validation.d.ts.map +1 -0
  82. package/dist/esm/utils/validation.mjs +117 -0
  83. package/dist/index.d.ts +9 -0
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +15 -0
  86. package/dist/prometheus-service.d.ts +1 -2
  87. package/dist/prometheus-service.d.ts.map +1 -1
  88. package/dist/resource-attribute-assignment.d.ts +24 -0
  89. package/dist/resource-attribute-assignment.d.ts.map +1 -0
  90. package/dist/resource-attribute-assignment.js +36 -0
  91. package/dist/resource-attributes-constants.d.ts +15 -0
  92. package/dist/resource-attributes-constants.d.ts.map +1 -0
  93. package/dist/resource-attributes-constants.js +28 -0
  94. package/dist/testKit/index.d.ts +4 -4
  95. package/dist/testKit/index.d.ts.map +1 -1
  96. package/dist/types/authorization-attributes-contracts.d.ts +27 -12
  97. package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
  98. package/dist/types/authorization-attributes-contracts.js +5 -5
  99. package/dist/types/authorization-attributes-service.interface.d.ts +57 -0
  100. package/dist/types/authorization-attributes-service.interface.d.ts.map +1 -0
  101. package/dist/types/authorization-attributes-service.interface.js +1 -0
  102. package/dist/types/general.d.ts +1 -2
  103. package/dist/types/general.d.ts.map +1 -1
  104. package/dist/utils/validation.d.ts +45 -0
  105. package/dist/utils/validation.d.ts.map +1 -0
  106. package/dist/utils/validation.js +119 -0
  107. package/package.json +3 -2
  108. package/src/authorization-attributes-ms-service.ts +528 -0
  109. package/src/authorization-attributes-service.ts +35 -222
  110. package/src/authorization-attributes-sns-service.ts +312 -0
  111. package/src/authorization-middleware.ts +2 -2
  112. package/src/authorization-service.ts +15 -75
  113. package/src/base-attribute-assignment.ts +55 -0
  114. package/src/constants/sns.ts +19 -2
  115. package/src/entity-attribute-assignment.ts +21 -0
  116. package/src/entity-attributes-constants.ts +7 -0
  117. package/src/errors/argument-error.ts +7 -0
  118. package/src/index.ts +9 -0
  119. package/src/prometheus-service.ts +1 -2
  120. package/src/resource-attribute-assignment.ts +43 -0
  121. package/src/resource-attributes-constants.ts +35 -0
  122. package/src/testKit/index.ts +5 -5
  123. package/src/types/authorization-attributes-contracts.ts +36 -11
  124. package/src/types/authorization-attributes-service.interface.ts +100 -0
  125. package/src/types/general.ts +3 -2
  126. package/src/utils/validation.ts +114 -0
@@ -3,7 +3,7 @@ import { MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
3
3
  import { Api } from '@mondaydotcomorg/trident-backend-api';
4
4
  import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
5
5
  import { getIgniteClient, IgniteClient } from '@mondaydotcomorg/ignite-sdk';
6
- import { Action, AuthorizationObject, AuthorizationParams, Resource } from './types/general';
6
+ import { AuthorizationObject, AuthorizationParams, Resource } from './types/general';
7
7
  import { sendAuthorizationCheckResponseTimeMetric } from './prometheus-service';
8
8
  import { recordAuthorizationTiming } from './metrics-service';
9
9
  import {
@@ -74,7 +74,7 @@ export class AuthorizationService {
74
74
  accountId: number,
75
75
  userId: number,
76
76
  resources: Resource[],
77
- action: Action
77
+ action: string
78
78
  ): Promise<AuthorizeResponse>;
79
79
 
80
80
  static async isAuthorized(
@@ -155,60 +155,19 @@ export class AuthorizationService {
155
155
  logger.error({ tag: 'authorization-service' }, 'AuthorizationService: igniteClient is not set, failing request');
156
156
  throw new Error('AuthorizationService: igniteClient is not set, failing request');
157
157
  }
158
-
159
- const allowedProfiles = this.igniteClient.configuration.getObjectValue<string[]>(
160
- ALLOWED_SDK_PLATFORM_PROFILES_KEY,
161
- []
162
- );
163
- const isAllowedProfile = allowedProfiles.includes(appName);
164
- logger.error(
165
- { tag: 'auth-debug', accountId, userId, appName, allowedProfiles, isAllowedProfile },
166
- 'AuthorizationService.getProfile: checking allowed profiles'
167
- );
168
-
169
- if (isAllowedProfile) {
170
- const profile = getProfile();
171
- logger.error(
172
- { tag: 'auth-debug', accountId, userId, appName, profile },
173
- 'AuthorizationService.getProfile: selected profile via allowed profiles'
174
- );
175
- return profile;
158
+ if (
159
+ this.igniteClient.configuration.getObjectValue<string[]>(ALLOWED_SDK_PLATFORM_PROFILES_KEY, []).includes(appName)
160
+ ) {
161
+ return getProfile();
176
162
  }
177
-
178
- const inReleaseProfiles = this.igniteClient.configuration.getObjectValue<string[]>(
179
- IN_RELEASE_SDK_PLATFORM_PROFILES_KEY,
180
- []
181
- );
182
- const isInReleaseProfile = inReleaseProfiles.includes(appName);
183
- const isFeatureFlagReleased = this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId });
184
-
185
- logger.error(
186
- {
187
- tag: 'auth-debug',
188
- accountId,
189
- userId,
190
- appName,
191
- inReleaseProfiles,
192
- isInReleaseProfile,
193
- isFeatureFlagReleased,
194
- featureFlag: PLATFORM_PROFILE_RELEASE_FF,
195
- },
196
- 'AuthorizationService.getProfile: checking feature flag release'
197
- );
198
-
199
- if (isInReleaseProfile && isFeatureFlagReleased) {
200
- const profile = getProfile();
201
- logger.error(
202
- { tag: 'auth-debug', accountId, userId, appName, profile },
203
- 'AuthorizationService.getProfile: selected profile via feature flag release'
204
- );
205
- return profile;
163
+ if (
164
+ this.igniteClient.configuration
165
+ .getObjectValue<string[]>(IN_RELEASE_SDK_PLATFORM_PROFILES_KEY, [])
166
+ .includes(appName) &&
167
+ this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })
168
+ ) {
169
+ return getProfile();
206
170
  }
207
-
208
- logger.error(
209
- { tag: 'auth-debug', accountId, userId, appName, profile: PlatformProfile.APP },
210
- 'AuthorizationService.getProfile: selected default APP profile'
211
- );
212
171
  return PlatformProfile.APP;
213
172
  }
214
173
 
@@ -225,34 +184,15 @@ export class AuthorizationService {
225
184
  this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId })
226
185
  );
227
186
 
228
- logger.error(
229
- {
230
- tag: 'auth-debug',
231
- accountId,
232
- userId,
233
- shouldNavigateToGraph,
234
- featureFlag: NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF,
235
- },
236
- 'AuthorizationService.canActionInScopeMultiple: determining which API flow to use'
237
- );
238
-
239
187
  const startTime = performance.now();
240
188
  let scopedActionResponseObjects: ScopedActionResponseObject[];
241
189
  let apiType: 'graph' | 'platform';
242
190
 
243
191
  if (shouldNavigateToGraph) {
244
192
  apiType = 'graph';
245
- logger.error(
246
- { tag: 'auth-debug', accountId, userId, apiType },
247
- 'AuthorizationService.canActionInScopeMultiple: using graph API flow'
248
- );
249
193
  scopedActionResponseObjects = await this.graphApi.checkPermissions(accountId, userId, scopedActions);
250
194
  } else {
251
195
  apiType = 'platform';
252
- logger.error(
253
- { tag: 'auth-debug', accountId, userId, apiType },
254
- 'AuthorizationService.canActionInScopeMultiple: using platform API flow'
255
- );
256
196
  const profile = this.getProfile(accountId, userId);
257
197
  const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
258
198
 
@@ -283,7 +223,7 @@ export class AuthorizationService {
283
223
  accountId: number,
284
224
  userId: number,
285
225
  resources: Resource[],
286
- action: Action
226
+ action: string
287
227
  ): Promise<AuthorizeResponse> {
288
228
  const { authorizationObjects } = createAuthorizationParams(resources, action);
289
229
  return this.isAuthorizedMultiple(accountId, userId, authorizationObjects);
@@ -398,7 +338,7 @@ export async function setIgniteClient() {
398
338
  AuthorizationInternalService.setIgniteClient(igniteClient);
399
339
  }
400
340
 
401
- export function createAuthorizationParams(resources: Resource[], action: Action): AuthorizationParams {
341
+ export function createAuthorizationParams(resources: Resource[], action: string): AuthorizationParams {
402
342
  const params = {
403
343
  authorizationObjects: resources.map((resource: Resource) => {
404
344
  const authorizationObject: AuthorizationObject = {
@@ -0,0 +1,55 @@
1
+ import { ValidationUtils } from './utils/validation';
2
+
3
+ /**
4
+ * Base class for attribute assignments (Resource or Entity)
5
+ * Provides common validation and functionality
6
+ */
7
+ export abstract class BaseAttributeAssignment<TId extends number, TType extends string> {
8
+ public readonly id: TId;
9
+ public readonly type: TType;
10
+ public readonly attributeKey: string;
11
+ public readonly attributeValue: string;
12
+
13
+ constructor(
14
+ id: TId,
15
+ type: string,
16
+ attributeKey: string,
17
+ attributeValue: string,
18
+ validTypes: readonly string[],
19
+ idFieldName: string,
20
+ typeFieldName: string
21
+ ) {
22
+ // Validate id
23
+ ValidationUtils.validateInteger(id, idFieldName);
24
+
25
+ // Validate type
26
+ this.type = ValidationUtils.validateEnum(type, validTypes as readonly TType[], typeFieldName) as TType;
27
+
28
+ // Validate attributeKey
29
+ ValidationUtils.validateString(attributeKey, 'attributeKey');
30
+
31
+ // Validate attributeValue
32
+ ValidationUtils.validateString(attributeValue, 'attributeValue');
33
+
34
+ this.id = id;
35
+ this.attributeKey = attributeKey;
36
+ this.attributeValue = attributeValue;
37
+ }
38
+
39
+ /**
40
+ * Compares two assignments for equality
41
+ * @param other Another assignment instance
42
+ * @returns true if all properties are equal
43
+ */
44
+ equals(other: BaseAttributeAssignment<TId, TType>): boolean {
45
+ if (!(other instanceof this.constructor)) {
46
+ return false;
47
+ }
48
+ return (
49
+ this.id === other.id &&
50
+ this.type === other.type &&
51
+ this.attributeKey === other.attributeKey &&
52
+ this.attributeValue === other.attributeValue
53
+ );
54
+ }
55
+ }
@@ -1,5 +1,22 @@
1
- export const SNS_ARN_ENV_VAR_NAME = 'SHARED_AUTHORIZATION_SNS_ENDPOINT_RESOURCE_ATTRIBUTES';
2
- export const SNS_DEV_TEST_NAME =
1
+ export enum SnsTopicType {
2
+ RESOURCE = 'resource',
3
+ ENTITY = 'entity',
4
+ }
5
+
6
+ // Resource SNS constants
7
+ export const RESOURCE_SNS_ARN_ENV_VAR_NAME = 'SHARED_AUTHORIZATION_SNS_ENDPOINT_RESOURCE_ATTRIBUTES';
8
+ export const RESOURCE_SNS_DEV_TEST_NAME =
3
9
  'arn:aws:sns:us-east-1:000000000000:monday-authorization-resource-attributes-sns-local';
10
+
11
+ // Entity SNS constants
12
+ export const ENTITY_SNS_ARN_ENV_VAR_NAME = 'SHARED_AUTHORIZATION_SNS_ENDPOINT_ENTITY_ATTRIBUTES';
13
+ export const ENTITY_SNS_DEV_TEST_NAME =
14
+ 'arn:aws:sns:us-east-1:000000000000:monday-authorization-entity-attributes-sns-local';
4
15
  export const RESOURCE_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND = 'resourceAttributeModification';
16
+ export const ENTITY_ATTRIBUTES_SNS_UPDATE_OPERATION_MESSAGE_KIND = 'entityAttributeModification';
5
17
  export const ASYNC_RESOURCE_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE = 100;
18
+ export const ASYNC_ENTITY_ATTRIBUTES_MAX_OPERATIONS_PER_MESSAGE = 100;
19
+
20
+ // Legacy exports for backward compatibility
21
+ export const SNS_ARN_ENV_VAR_NAME = RESOURCE_SNS_ARN_ENV_VAR_NAME;
22
+ export const SNS_DEV_TEST_NAME = RESOURCE_SNS_DEV_TEST_NAME;
@@ -0,0 +1,21 @@
1
+ import { ENTITY_TYPES, EntityType } from './entity-attributes-constants';
2
+ import { BaseAttributeAssignment } from './base-attribute-assignment';
3
+
4
+ export class EntityAttributeAssignment extends BaseAttributeAssignment<number, EntityType> {
5
+ public readonly entityId: number;
6
+ public readonly entityType: EntityType;
7
+
8
+ constructor(entityId: number, entityType: string, attributeKey: string, attributeValue: string) {
9
+ super(entityId, entityType, attributeKey, attributeValue, Object.values(ENTITY_TYPES), 'entityId', 'entityType');
10
+ this.entityId = entityId;
11
+ this.entityType = this.type;
12
+ }
13
+ /**
14
+ * Compares two assignments for equality
15
+ * @param other Another EntityAttributeAssignment instance
16
+ * @returns true if all properties are equal
17
+ */
18
+ equals(other: EntityAttributeAssignment): boolean {
19
+ return super.equals(other);
20
+ }
21
+ }
@@ -0,0 +1,7 @@
1
+ export const ENTITY_TYPES = {
2
+ USER: 'user',
3
+ TEAM: 'team',
4
+ ACCOUNT: 'account',
5
+ } as const;
6
+
7
+ export type EntityType = (typeof ENTITY_TYPES)[keyof typeof ENTITY_TYPES];
@@ -0,0 +1,7 @@
1
+ export class ArgumentError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'ArgumentError';
5
+ Object.setPrototypeOf(this, ArgumentError.prototype);
6
+ }
7
+ }
package/src/index.ts CHANGED
@@ -58,6 +58,15 @@ export {
58
58
  } from './authorization-middleware';
59
59
  export { AuthorizationService, AuthorizeResponse } from './authorization-service';
60
60
  export { AuthorizationAttributesService } from './authorization-attributes-service';
61
+ export { AuthorizationAttributesSnsService } from './authorization-attributes-sns-service';
62
+ export { AuthorizationAttributesMsService } from './authorization-attributes-ms-service';
63
+ export { IAuthorizationAttributesService } from './types/authorization-attributes-service.interface';
64
+ export { ResourceAttributeAssignment } from './resource-attribute-assignment';
65
+ export { RESOURCE_TYPES, RESOURCE_ATTRIBUTES_CONSTANTS } from './resource-attributes-constants';
66
+ export { EntityAttributeAssignment } from './entity-attribute-assignment';
67
+ export { ENTITY_TYPES } from './entity-attributes-constants';
68
+ export { ArgumentError } from './errors/argument-error';
69
+ export type { EntityType } from './entity-attributes-constants';
61
70
  export { RolesService } from './roles-service';
62
71
  export { MembershipsService } from './memberships';
63
72
  export { AuthorizationObject, Resource, BaseRequest, ResourceGetter, ContextGetter } from './types/general';
@@ -1,4 +1,3 @@
1
- import { Action } from './types/general';
2
1
 
3
2
  let prometheus: any = null;
4
3
  let authorizationCheckResponseTimeMetric: any = null;
@@ -36,7 +35,7 @@ export function getMetricsManager() {
36
35
 
37
36
  export function sendAuthorizationCheckResponseTimeMetric(
38
37
  resourceType: string,
39
- action: Action,
38
+ action: string,
40
39
  isAuthorized: boolean,
41
40
  responseStatus: number,
42
41
  time: number
@@ -0,0 +1,43 @@
1
+ import { RESOURCE_TYPES, ResourceType } from './resource-attributes-constants';
2
+ import { BaseAttributeAssignment } from './base-attribute-assignment';
3
+
4
+ export class ResourceAttributeAssignment extends BaseAttributeAssignment<number, ResourceType> {
5
+ public readonly resourceId: number;
6
+ public readonly resourceType: ResourceType;
7
+
8
+ constructor(resourceId: number, resourceType: string, attributeKey: string, attributeValue: string) {
9
+ super(
10
+ resourceId,
11
+ resourceType,
12
+ attributeKey,
13
+ attributeValue,
14
+ Object.values(RESOURCE_TYPES),
15
+ 'resourceId',
16
+ 'resourceType'
17
+ );
18
+ this.resourceId = resourceId;
19
+ this.resourceType = this.type;
20
+ }
21
+
22
+ /**
23
+ * Converts the assignment to a plain object with camelCase keys
24
+ * @returns Plain object with camelCase keys: { resourceId, resourceType, key, value }
25
+ */
26
+ toPlainObject(): { resourceId: number; resourceType: string; key: string; value: string } {
27
+ return {
28
+ resourceId: this.resourceId,
29
+ resourceType: this.resourceType,
30
+ key: this.attributeKey,
31
+ value: this.attributeValue,
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Compares two assignments for equality
37
+ * @param other Another ResourceAttributeAssignment instance
38
+ * @returns true if all properties are equal
39
+ */
40
+ equals(other: ResourceAttributeAssignment): boolean {
41
+ return super.equals(other);
42
+ }
43
+ }
@@ -0,0 +1,35 @@
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 Record<string, ResourceType>;
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 =
27
+ | 'account'
28
+ | 'account_product'
29
+ | 'workspace'
30
+ | 'board'
31
+ | 'item'
32
+ | 'team'
33
+ | 'overview'
34
+ | 'document'
35
+ | 'crm';
@@ -1,4 +1,4 @@
1
- import { Action, BaseRequest, BaseResponse, ContextGetter, Resource, ResourceGetter } from '../types/general';
1
+ import { BaseRequest, BaseResponse, ContextGetter, Resource, ResourceGetter } from '../types/general';
2
2
  import { defaultContextGetter } from '../authorization-middleware';
3
3
  import { AuthorizationInternalService } from '../authorization-internal-service';
4
4
  import type { NextFunction } from 'express';
@@ -7,11 +7,11 @@ export type TestPermittedAction = {
7
7
  accountId: number;
8
8
  userId: number;
9
9
  resources: Resource[];
10
- action: Action;
10
+ action: string;
11
11
  };
12
12
 
13
13
  let testPermittedActions: TestPermittedAction[] = [];
14
- export const addTestPermittedAction = (accountId: number, userId: number, resources: Resource[], action: Action) => {
14
+ export const addTestPermittedAction = (accountId: number, userId: number, resources: Resource[], action: string) => {
15
15
  testPermittedActions.push({ accountId, userId, resources, action });
16
16
  };
17
17
 
@@ -19,7 +19,7 @@ export const clearTestPermittedActions = () => {
19
19
  testPermittedActions = [];
20
20
  };
21
21
 
22
- const isActionAuthorized = (accountId: number, userId: number, resources: Resource[], action: Action) => {
22
+ const isActionAuthorized = (accountId: number, userId: number, resources: Resource[], action: string) => {
23
23
  // If no resources to check, deny access
24
24
  if (resources.length === 0) {
25
25
  return { isAuthorized: false };
@@ -46,7 +46,7 @@ const isActionAuthorized = (accountId: number, userId: number, resources: Resour
46
46
  };
47
47
 
48
48
  export const getTestAuthorizationMiddleware = (
49
- action: Action,
49
+ action: string,
50
50
  resourceGetter: ResourceGetter,
51
51
  contextGetter?: ContextGetter
52
52
  ) => {
@@ -1,33 +1,58 @@
1
1
  import { Resource } from './general';
2
+ import type { EntityType } from '../entity-attributes-constants';
3
+ import type { ResourceType } from '../resource-attributes-constants';
2
4
 
3
- export interface ResourceAttributeAssignment {
4
- resourceType: Resource['type'];
5
- resourceId: Resource['id'];
5
+ export type { EntityType, ResourceType };
6
+
7
+ interface AttributeAssignment {
6
8
  key: string;
7
9
  value: string;
8
10
  }
9
11
 
10
- export interface ResourceAttributeResponse {
11
- attributes: ResourceAttributeAssignment[];
12
+ // Resource Attribute Assignment - matching API contract
13
+ export interface ResourceAttributeAssignment extends AttributeAssignment {
14
+ resourceId: number;
15
+ resourceType: ResourceType;
16
+ }
17
+
18
+ // Entity Attribute Assignment - matching API contract
19
+ // Note: For validation, use the EntityAttributeAssignment class from '../entity-attribute-assignment'
20
+ export interface EntityAttributeAssignment extends AttributeAssignment {
21
+ entityId: number;
22
+ entityType: EntityType;
12
23
  }
13
24
 
25
+ // Legacy types for backward compatibility
14
26
  export interface ResourceAttributeDelete {
15
27
  resourceType: Resource['type'];
16
28
  resourceId: Resource['id'];
17
29
  key: string;
18
30
  }
19
31
 
20
- export enum ResourceAttributeOperationEnum {
32
+ export interface EntityAttributeDelete {
33
+ entityType: EntityType;
34
+ entityId: number;
35
+ key: string;
36
+ }
37
+
38
+ export enum AttributeOperation {
21
39
  UPSERT = 'upsert',
22
40
  DELETE = 'delete',
23
41
  }
24
42
 
25
- interface UpsertResourceAttributeOperation extends ResourceAttributeAssignment {
26
- operationType: ResourceAttributeOperationEnum.UPSERT;
43
+ // Response types
44
+ export interface ResourceAttributeResponse {
45
+ attributes: ResourceAttributeAssignment[];
27
46
  }
28
47
 
29
- interface DeleteResourceAttributeOperation extends ResourceAttributeDelete {
30
- operationType: ResourceAttributeOperationEnum.DELETE;
48
+ export interface EntityAttributeResponse {
49
+ attributes: EntityAttributeAssignment[];
31
50
  }
32
51
 
33
- export type ResourceAttributesOperation = UpsertResourceAttributeOperation | DeleteResourceAttributeOperation;
52
+ export interface ResourceAttributeOperation extends ResourceAttributeAssignment {
53
+ operationType: AttributeOperation;
54
+ }
55
+
56
+ export interface EntityAttributeOperation extends EntityAttributeAssignment {
57
+ operationType: AttributeOperation;
58
+ }
@@ -0,0 +1,100 @@
1
+ import {
2
+ ResourceAttributeAssignment as ResourceAttributeAssignmentContract,
3
+ EntityAttributeAssignment as EntityAttributeAssignmentContract,
4
+ EntityType,
5
+ } from './authorization-attributes-contracts';
6
+ import { ResourceAttributeOperation, EntityAttributeOperation } from './authorization-attributes-contracts';
7
+ import { ResourceAttributeAssignment } from '../resource-attribute-assignment';
8
+ import { EntityAttributeAssignment } from '../entity-attribute-assignment';
9
+ import { Resource } from './general';
10
+
11
+ /**
12
+ * Resource type compatible with both MS and SNS services
13
+ */
14
+ export interface CompatibleResource {
15
+ resourceType?: string;
16
+ resourceId?: number;
17
+ type?: string;
18
+ id?: number;
19
+ }
20
+
21
+ /**
22
+ * Interface for authorization attributes operations.
23
+ * Both MS (direct) and SNS (async) services implement this interface.
24
+ */
25
+ export interface IAuthorizationAttributesService {
26
+ /**
27
+ * Upserts resource attributes.
28
+ * For MS service: returns Promise<void>
29
+ * For SNS service: requires appName and callerActionIdentifier, returns Promise<ResourceAttributesOperation[]>
30
+ */
31
+ upsertResourceAttributes(
32
+ accountId: number,
33
+ resourceAttributeAssignments: ResourceAttributeAssignment[] | ResourceAttributeAssignmentContract[],
34
+ appName?: string,
35
+ callerActionIdentifier?: string
36
+ ): Promise<void | ResourceAttributeOperation[]>;
37
+
38
+ /**
39
+ * Deletes resource attributes.
40
+ * For MS service: returns Promise<void>
41
+ * For SNS service: requires appName and callerActionIdentifier, returns Promise<ResourceAttributesOperation[]>
42
+ */
43
+ deleteResourceAttributes(
44
+ accountId: number,
45
+ resource: CompatibleResource | Resource,
46
+ attributeKeys: string[],
47
+ appName?: string,
48
+ callerActionIdentifier?: string
49
+ ): Promise<void | ResourceAttributeOperation[]>;
50
+
51
+ /**
52
+ * Upserts entity attributes.
53
+ * For MS service: returns Promise<void>
54
+ * For SNS service: requires appName and callerActionIdentifier, returns Promise<EntityAttributesOperation[]>
55
+ */
56
+ upsertEntityAttributes(
57
+ accountId: number,
58
+ entityAttributeAssignments: EntityAttributeAssignment[] | EntityAttributeAssignmentContract[],
59
+ appName?: string,
60
+ callerActionIdentifier?: string
61
+ ): Promise<void | EntityAttributeOperation[]>;
62
+
63
+ /**
64
+ * Deletes entity attributes.
65
+ * For MS service: returns Promise<void>
66
+ * For SNS service: requires appName and callerActionIdentifier, returns Promise<EntityAttributesOperation[]>
67
+ */
68
+ deleteEntityAttributes(
69
+ accountId: number,
70
+ entityType: EntityType | string,
71
+ entityId: number,
72
+ attributeKeys: string[],
73
+ appName?: string,
74
+ callerActionIdentifier?: string
75
+ ): Promise<void | EntityAttributeOperation[]>;
76
+
77
+ /**
78
+ * Updates resource attributes (batch operations).
79
+ * For MS service: may throw error or delegate to upsert/delete
80
+ * For SNS service: returns Promise<ResourceAttributesOperation[]>
81
+ */
82
+ updateResourceAttributes(
83
+ accountId: number,
84
+ appName: string,
85
+ callerActionIdentifier: string,
86
+ resourceAttributeOperations: ResourceAttributeOperation[]
87
+ ): Promise<ResourceAttributeOperation[]>;
88
+
89
+ /**
90
+ * Updates entity attributes (batch operations).
91
+ * For MS service: may throw error or delegate to upsert/delete
92
+ * For SNS service: returns Promise<EntityAttributesOperation[]>
93
+ */
94
+ updateEntityAttributes(
95
+ accountId: number,
96
+ appName: string,
97
+ callerActionIdentifier: string,
98
+ entityAttributeOperations: EntityAttributeOperation[]
99
+ ): Promise<EntityAttributeOperation[]>;
100
+ }
@@ -5,16 +5,17 @@ export interface Resource {
5
5
  type: string;
6
6
  wrapperData?: object;
7
7
  }
8
- export type Action = string;
8
+
9
9
  export interface Context {
10
10
  accountId: number;
11
11
  userId: number;
12
12
  }
13
+
13
14
  export interface AuthorizationObject {
14
15
  resource_id?: Resource['id'];
15
16
  resource_type: Resource['type'];
16
17
  wrapper_data?: Resource['wrapperData'];
17
- action: Action;
18
+ action: string;
18
19
  }
19
20
  export interface AuthorizationParams {
20
21
  authorizationObjects: AuthorizationObject[];