@mondaydotcomorg/monday-authorization 3.7.0-feat-shaime-support-entity-attributes-4-49e1de0 → 3.7.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.
Files changed (115) hide show
  1. package/README.md +7 -1
  2. package/dist/authorization-attributes-ms-service.d.ts +20 -40
  3. package/dist/authorization-attributes-ms-service.d.ts.map +1 -1
  4. package/dist/authorization-attributes-ms-service.js +48 -103
  5. package/dist/authorization-attributes-service.d.ts +12 -10
  6. package/dist/authorization-attributes-service.d.ts.map +1 -1
  7. package/dist/authorization-attributes-service.js +17 -15
  8. package/dist/authorization-attributes-sns-service.d.ts +37 -44
  9. package/dist/authorization-attributes-sns-service.d.ts.map +1 -1
  10. package/dist/authorization-attributes-sns-service.js +53 -90
  11. package/dist/authorization-service.d.ts +0 -1
  12. package/dist/authorization-service.d.ts.map +1 -1
  13. package/dist/authorization-service.js +2 -22
  14. package/dist/base-attribute-assignment.d.ts +6 -7
  15. package/dist/base-attribute-assignment.d.ts.map +1 -1
  16. package/dist/base-attribute-assignment.js +5 -7
  17. package/dist/base-authorization-attributes-service.d.ts +32 -0
  18. package/dist/base-authorization-attributes-service.d.ts.map +1 -0
  19. package/dist/base-authorization-attributes-service.js +63 -0
  20. package/dist/entity-attribute-assignment.d.ts +4 -8
  21. package/dist/entity-attribute-assignment.d.ts.map +1 -1
  22. package/dist/entity-attribute-assignment.js +3 -4
  23. package/dist/esm/authorization-attributes-ms-service.d.ts +20 -40
  24. package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -1
  25. package/dist/esm/authorization-attributes-ms-service.mjs +48 -103
  26. package/dist/esm/authorization-attributes-service.d.ts +12 -10
  27. package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
  28. package/dist/esm/authorization-attributes-service.mjs +17 -15
  29. package/dist/esm/authorization-attributes-sns-service.d.ts +37 -44
  30. package/dist/esm/authorization-attributes-sns-service.d.ts.map +1 -1
  31. package/dist/esm/authorization-attributes-sns-service.mjs +53 -90
  32. package/dist/esm/authorization-service.d.ts +0 -1
  33. package/dist/esm/authorization-service.d.ts.map +1 -1
  34. package/dist/esm/authorization-service.mjs +3 -23
  35. package/dist/esm/base-attribute-assignment.d.ts +6 -7
  36. package/dist/esm/base-attribute-assignment.d.ts.map +1 -1
  37. package/dist/esm/base-attribute-assignment.mjs +5 -7
  38. package/dist/esm/base-authorization-attributes-service.d.ts +32 -0
  39. package/dist/esm/base-authorization-attributes-service.d.ts.map +1 -0
  40. package/dist/esm/base-authorization-attributes-service.mjs +61 -0
  41. package/dist/esm/entity-attribute-assignment.d.ts +4 -8
  42. package/dist/esm/entity-attribute-assignment.d.ts.map +1 -1
  43. package/dist/esm/entity-attribute-assignment.mjs +3 -4
  44. package/dist/esm/index.d.ts +6 -0
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/index.mjs +6 -0
  47. package/dist/esm/resource-attribute-assignment.d.ts +3 -7
  48. package/dist/esm/resource-attribute-assignment.d.ts.map +1 -1
  49. package/dist/esm/resource-attribute-assignment.mjs +8 -2
  50. package/dist/esm/resource-attributes-constants.d.ts +13 -10
  51. package/dist/esm/resource-attributes-constants.d.ts.map +1 -1
  52. package/dist/esm/resource-attributes-constants.mjs +5 -2
  53. package/dist/esm/testKit/index.d.ts +4 -4
  54. package/dist/esm/testKit/index.d.ts.map +1 -1
  55. package/dist/esm/types/authorization-attributes-contracts.d.ts +7 -21
  56. package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
  57. package/dist/esm/types/general.d.ts +4 -3
  58. package/dist/esm/types/general.d.ts.map +1 -1
  59. package/dist/esm/utils/assignment-schema.d.ts +51 -0
  60. package/dist/esm/utils/assignment-schema.d.ts.map +1 -0
  61. package/dist/esm/utils/assignment-schema.mjs +54 -0
  62. package/dist/esm/utils/resource-schema.d.ts +9 -0
  63. package/dist/esm/utils/resource-schema.d.ts.map +1 -0
  64. package/dist/esm/utils/resource-schema.mjs +16 -0
  65. package/dist/esm/utils/validation.d.ts +11 -28
  66. package/dist/esm/utils/validation.d.ts.map +1 -1
  67. package/dist/esm/utils/validation.mjs +61 -118
  68. package/dist/index.d.ts +6 -0
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +24 -0
  71. package/dist/resource-attribute-assignment.d.ts +3 -7
  72. package/dist/resource-attribute-assignment.d.ts.map +1 -1
  73. package/dist/resource-attribute-assignment.js +8 -2
  74. package/dist/resource-attributes-constants.d.ts +13 -10
  75. package/dist/resource-attributes-constants.d.ts.map +1 -1
  76. package/dist/resource-attributes-constants.js +5 -2
  77. package/dist/testKit/index.d.ts +4 -4
  78. package/dist/testKit/index.d.ts.map +1 -1
  79. package/dist/types/authorization-attributes-contracts.d.ts +7 -21
  80. package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
  81. package/dist/types/general.d.ts +4 -3
  82. package/dist/types/general.d.ts.map +1 -1
  83. package/dist/utils/assignment-schema.d.ts +51 -0
  84. package/dist/utils/assignment-schema.d.ts.map +1 -0
  85. package/dist/utils/assignment-schema.js +63 -0
  86. package/dist/utils/resource-schema.d.ts +9 -0
  87. package/dist/utils/resource-schema.d.ts.map +1 -0
  88. package/dist/utils/resource-schema.js +22 -0
  89. package/dist/utils/validation.d.ts +11 -28
  90. package/dist/utils/validation.d.ts.map +1 -1
  91. package/dist/utils/validation.js +61 -118
  92. package/package.json +2 -3
  93. package/src/authorization-attributes-ms-service.ts +92 -154
  94. package/src/authorization-attributes-service.ts +18 -16
  95. package/src/authorization-attributes-sns-service.ts +132 -131
  96. package/src/authorization-service.ts +3 -28
  97. package/src/base-attribute-assignment.ts +10 -26
  98. package/src/base-authorization-attributes-service.ts +90 -0
  99. package/src/entity-attribute-assignment.ts +7 -6
  100. package/src/index.ts +17 -0
  101. package/src/resource-attribute-assignment.ts +13 -10
  102. package/src/resource-attributes-constants.ts +5 -2
  103. package/src/testKit/index.ts +5 -5
  104. package/src/types/authorization-attributes-contracts.ts +7 -27
  105. package/src/types/general.ts +4 -3
  106. package/src/utils/assignment-schema.ts +56 -0
  107. package/src/utils/resource-schema.ts +16 -0
  108. package/src/utils/validation.ts +90 -137
  109. package/dist/esm/types/authorization-attributes-service.interface.d.ts +0 -57
  110. package/dist/esm/types/authorization-attributes-service.interface.d.ts.map +0 -1
  111. package/dist/esm/types/authorization-attributes-service.interface.mjs +0 -1
  112. package/dist/types/authorization-attributes-service.interface.d.ts +0 -57
  113. package/dist/types/authorization-attributes-service.interface.d.ts.map +0 -1
  114. package/dist/types/authorization-attributes-service.interface.js +0 -1
  115. package/src/types/authorization-attributes-service.interface.ts +0 -101
@@ -2,6 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const Ajv = require('ajv');
4
4
  const errors_argumentError = require('../errors/argument-error.js');
5
+ const utils_assignmentSchema = require('./assignment-schema.js');
6
+ const utils_resourceSchema = require('./resource-schema.js');
5
7
 
6
8
  const _interopDefault = e => e && e.__esModule ? e : { default: e };
7
9
 
@@ -12,146 +14,87 @@ const Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
12
14
  */
13
15
  class ValidationUtils {
14
16
  static ajv = new Ajv__default.default({ allErrors: true });
15
- /**
16
- * Validates that a value is an integer. Throws ArgumentError with a descriptive message on failure.
17
- */
17
+ static integerValidator = this.ajv.compile({ type: 'number', multipleOf: 1 });
18
+ static stringValidator = this.ajv.compile({ type: 'string', minLength: 1 });
19
+ static stringArrayValidator = this.ajv.compile({
20
+ type: 'array',
21
+ items: { type: 'string' },
22
+ });
18
23
  static validateInteger(value) {
19
- const numberSchema = { type: 'number', multipleOf: 1 };
20
- const validate = ValidationUtils.ajv.compile(numberSchema);
21
- const isValid = validate(value);
22
- if (!isValid) {
23
- throw new errors_argumentError.ArgumentError(`Value must be an integer, got: ${value}`);
24
+ const valid = this.integerValidator(value);
25
+ if (!valid) {
26
+ throw new errors_argumentError.ArgumentError('Invalid integer');
24
27
  }
25
28
  }
26
- /**
27
- * Validates that a value is a non-empty string. Throws ArgumentError on failure.
28
- */
29
29
  static validateString(value) {
30
- const non_empty_string_schema = {
31
- type: 'string',
32
- minLength: 1,
33
- pattern: '\\S',
34
- };
35
- const validate = ValidationUtils.ajv.compile(non_empty_string_schema);
36
- const isValid = validate(value);
37
- if (!isValid) {
38
- throw new errors_argumentError.ArgumentError(`Value must be a non-empty string, got: ${value}`);
30
+ const valid = this.stringValidator(value);
31
+ if (!valid) {
32
+ throw new errors_argumentError.ArgumentError('Invalid string');
39
33
  }
40
34
  }
41
- /**
42
- * Validates that a value is an array of non-empty strings. Throws ArgumentError on failure.
43
- * Allows empty arrays - caller should handle early return.
44
- */
45
35
  static validateStringArray(value) {
46
- const string_array_schema = {
47
- type: 'array',
48
- items: {
49
- type: 'string',
50
- minLength: 1,
51
- pattern: '\\S',
52
- },
53
- };
54
- const validateStringArray = ValidationUtils.ajv.compile(string_array_schema);
55
- const isValid = validateStringArray(value);
36
+ const valid = this.stringArrayValidator(value);
37
+ if (!valid) {
38
+ throw new errors_argumentError.ArgumentError('Invalid string array');
39
+ }
40
+ }
41
+ static validateResource(resource) {
42
+ const isValid = utils_resourceSchema.resourceSchema(resource);
56
43
  if (!isValid) {
57
- throw new errors_argumentError.ArgumentError(`Value must be an array of non-empty strings, got: ${value}`);
44
+ const errorMessage = this.formatValidationErrors(utils_resourceSchema.resourceSchema.errors);
45
+ throw new errors_argumentError.ArgumentError(errorMessage ? `Invalid resource: ${errorMessage}` : 'Invalid resource');
58
46
  }
59
- // Allow empty arrays to pass validation - caller should handle early return
60
- // Non-empty arrays will be validated for string content above
61
47
  }
62
48
  /**
63
49
  * Validates an attribute assignment object using a single AJV schema.
64
50
  * Preserves legacy error messages for each field.
65
51
  */
66
- static validateAssignment(data, validTypes, fieldNames) {
67
- const schema = {
68
- type: 'object',
69
- properties: {
70
- id: { type: 'number', multipleOf: 1 },
71
- type: { type: 'string', enum: validTypes },
72
- attributeKey: { type: 'string', minLength: 1 },
73
- attributeValue: { type: 'string', minLength: 1 },
74
- },
75
- required: ['id', 'type', 'attributeKey', 'attributeValue'],
76
- additionalProperties: false,
77
- };
78
- const validate = this.ajv.compile(schema);
79
- const valid = validate(data);
52
+ static validatUpsertResourceAssignment(resource) {
53
+ const valid = utils_assignmentSchema.resourceUpsertAssignmentSchema(resource);
80
54
  if (!valid) {
81
- // Map to legacy error messages deterministically
82
- const { id, type, attributeKey, attributeValue } = data;
83
- // id must be integer
84
- const isInteger = typeof id === 'number' && Number.isFinite(id) && Math.floor(id) === id;
85
- if (!isInteger) {
86
- throw new errors_argumentError.ArgumentError(`${fieldNames.id} must be an integer, got: ${id}`);
87
- }
88
- // type must be within enum
89
- if (typeof type !== 'string' || !validTypes.includes(type)) {
90
- throw new errors_argumentError.ArgumentError(`${fieldNames.type} must be one of [${validTypes.join(', ')}], got: ${type}`);
91
- }
92
- // attributeKey
93
- if (typeof attributeKey !== 'string') {
94
- throw new errors_argumentError.ArgumentError(`attributeKey must be a string, got: ${typeof attributeKey}`);
95
- }
96
- if (!attributeKey) {
97
- throw new errors_argumentError.ArgumentError('attributeKey must be a non-empty string');
98
- }
99
- // attributeValue
100
- if (typeof attributeValue !== 'string') {
101
- throw new errors_argumentError.ArgumentError(`attributeValue must be a string, got: ${typeof attributeValue}`);
102
- }
103
- if (!attributeValue) {
104
- throw new errors_argumentError.ArgumentError('attributeValue must be a non-empty string');
105
- }
106
- // Fallback
107
- throw new errors_argumentError.ArgumentError('Invalid attribute assignment');
55
+ const errorMessage = this.formatValidationErrors(utils_assignmentSchema.resourceUpsertAssignmentSchema.errors);
56
+ throw new errors_argumentError.ArgumentError(errorMessage
57
+ ? `Invalid resource attribute assignment: ${errorMessage}`
58
+ : 'Invalid resource attribute assignment');
108
59
  }
109
- return {
110
- id: data.id,
111
- type: data.type,
112
- attributeKey: data.attributeKey,
113
- attributeValue: data.attributeValue,
114
- };
115
60
  }
116
- /**
117
- * Validates a Resource-like object shape: { id: number; type: string }.
118
- * Throws ArgumentError with legacy-compatible messages.
119
- */
120
- static validateResource(resource) {
121
- if (!resource || typeof resource !== 'object') {
122
- throw new errors_argumentError.ArgumentError('resource must be an object');
61
+ static validatDeleteResourceAssignment(resource) {
62
+ const valid = utils_assignmentSchema.resourceDeleteAssignmentSchema(resource);
63
+ if (!valid) {
64
+ const errorMessage = this.formatValidationErrors(utils_assignmentSchema.resourceDeleteAssignmentSchema.errors);
65
+ throw new errors_argumentError.ArgumentError(errorMessage
66
+ ? `Invalid resource attribute assignment: ${errorMessage}`
67
+ : 'Invalid resource attribute assignment');
123
68
  }
124
- const schema = {
125
- type: 'object',
126
- properties: {
127
- id: { type: 'number', multipleOf: 1 },
128
- type: { type: 'string', minLength: 1 },
129
- wrapperData: { type: 'string' },
130
- },
131
- required: ['type', 'id'],
132
- additionalProperties: false,
133
- };
134
- const validate = this.ajv.compile(schema);
135
- const isValid = validate(resource);
136
- if (!isValid) {
137
- throw new errors_argumentError.ArgumentError('Invalid resource');
69
+ }
70
+ static validatUpsertEntityAssignment(entity) {
71
+ const valid = utils_assignmentSchema.entityUpsertAssignmentSchema(entity);
72
+ if (!valid) {
73
+ const errorMessage = this.formatValidationErrors(utils_assignmentSchema.entityUpsertAssignmentSchema.errors);
74
+ throw new errors_argumentError.ArgumentError(errorMessage ? `Invalid entity attribute assignment: ${errorMessage}` : 'Invalid entity attribute assignment');
138
75
  }
139
76
  }
140
- static validateArrayTypeOf(attributesMessages, messageClass) {
141
- const arraySchema = {
142
- type: 'array',
143
- };
144
- const validateArray = ValidationUtils.ajv.compile(arraySchema);
145
- const isArrayValid = validateArray(attributesMessages);
146
- if (!isArrayValid) {
147
- throw new errors_argumentError.ArgumentError(`attributesMessages must be an array`);
77
+ static validatDeleteEntityAssignment(entity) {
78
+ const valid = utils_assignmentSchema.entityDeleteAssignmentSchema(entity);
79
+ if (!valid) {
80
+ const errorMessage = this.formatValidationErrors(utils_assignmentSchema.entityDeleteAssignmentSchema.errors);
81
+ throw new errors_argumentError.ArgumentError(errorMessage ? `Invalid entity attribute assignment: ${errorMessage}` : 'Invalid entity attribute assignment');
148
82
  }
149
- for (let i = 0; i < attributesMessages.length; i++) {
150
- const item = attributesMessages[i];
151
- if (!(item instanceof messageClass)) {
152
- throw new errors_argumentError.ArgumentError(`attributesMessages[${i}] must be an instance of ${messageClass.name}, got: ${item?.constructor?.name || typeof item}`);
153
- }
83
+ }
84
+ /**
85
+ * Formats AJV validation errors into a readable error message
86
+ */
87
+ static formatValidationErrors(errors) {
88
+ if (!errors || !errors.length) {
89
+ return '';
154
90
  }
91
+ return errors
92
+ .map(err => {
93
+ const path = err.instancePath || (err.params && 'missingProperty' in err.params ? `/${err.params.missingProperty}` : '');
94
+ const message = err.message || 'validation failed';
95
+ return path ? `${path}: ${message}` : message;
96
+ })
97
+ .join('; ');
155
98
  }
156
99
  }
157
100
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/monday-authorization",
3
- "version": "3.7.0-feat-shaime-support-entity-attributes-4-49e1de0",
3
+ "version": "3.7.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",
@@ -28,8 +28,7 @@
28
28
  "@mondaydotcomorg/monday-observability-kit": "^1.5.3",
29
29
  "@mondaydotcomorg/monday-sns": "^1.2.1",
30
30
  "@mondaydotcomorg/trident-backend-api": "^0.24.3",
31
- "ajv": "^8.17.1",
32
- "ajv-keywords": "^5.1.0",
31
+ "ajv": "^8.12.0",
33
32
  "lodash": "^4.17.21",
34
33
  "node-fetch": "^2.6.7",
35
34
  "on-headers": "^1.0.2",
@@ -3,18 +3,18 @@ import { signAuthorizationHeader } from '@mondaydotcomorg/monday-jwt';
3
3
  import { ResourceAttributeAssignment } from './resource-attribute-assignment';
4
4
  import { EntityAttributeAssignment } from './entity-attribute-assignment';
5
5
  import {
6
- AttributeOperation,
7
- ResourceAttributeOperation,
8
- EntityAttributeOperation,
6
+ ResourceAttributeUpsertOperation,
7
+ ResourceAttributeDeleteOperation,
8
+ EntityAttributeUpsertOperation,
9
+ EntityAttributeDeleteOperation,
9
10
  } from './types/authorization-attributes-contracts';
10
11
  import { EntityType } from './entity-attributes-constants';
11
- import { ArgumentError } from './errors/argument-error';
12
12
  import { AuthorizationInternalService, logger } from './authorization-internal-service';
13
13
  import { getAttributionsFromApi } from './attributions-service';
14
14
  import { APP_NAME } from './constants';
15
- import { ValidationUtils } from './utils/validation';
16
- import { AuthorizationAttributesService } from './types/authorization-attributes-service.interface';
15
+ import { BaseAuthorizationAttributesService } from './base-authorization-attributes-service';
17
16
  import { Resource } from './types/general';
17
+
18
18
  const INTERNAL_APP_NAME = 'internal_ms';
19
19
  const UPSERT_RESOURCE_ATTRIBUTES_PATH = '/attributes/{accountId}/resource';
20
20
  const DELETE_RESOURCE_ATTRIBUTES_PATH = '/attributes/{accountId}/resource/{resourceType}/{resourceId}';
@@ -29,206 +29,156 @@ interface DeleteRequestBody {
29
29
  * Service class for managing resource attributes in the authorization microservice.
30
30
  * Provides synchronous HTTP operations to create/update and delete attributes on resources.
31
31
  */
32
- export class AuthorizationAttributesMsService implements AuthorizationAttributesService {
32
+ export class AuthorizationAttributesMsService extends BaseAuthorizationAttributesService {
33
33
  private static LOG_TAG = 'authorization_attributes_ms';
34
- private static httpClient: HttpClient | null = Api.getPart('httpClient') ?? null;
35
-
36
- public static destroyHttpClient(): void {
37
- AuthorizationAttributesMsService.httpClient = null;
38
- }
34
+ private static httpClient: HttpClient | undefined = Api.getPart('httpClient');
39
35
 
40
- /**
41
- * Creates or updates resource attributes synchronously.
42
- * @param accountId The account ID
43
- * @param resourceAttributeAssignments Array of ResourceAttributeAssignment objects
44
- * @returns Promise<void>
45
- */
46
- async upsertResourceAttributes(
47
- accountId: number,
48
- resourceAttributeAssignments: ResourceAttributeAssignment[],
49
- _appName?: string,
50
- _callerActionIdentifier?: string
51
- ): Promise<void> {
52
- return AuthorizationAttributesMsService.executeUpsertRequest(
53
- accountId,
54
- resourceAttributeAssignments,
55
- UPSERT_RESOURCE_ATTRIBUTES_PATH,
56
- 'resourceAttributeAssignments',
57
- ResourceAttributeAssignment,
58
- 'resource',
59
- 'upsertResourceAttributes'
60
- );
36
+ constructor() {
37
+ super();
38
+ if (!AuthorizationAttributesMsService.httpClient) {
39
+ AuthorizationAttributesMsService.httpClient = Api.getPart('httpClient');
40
+ if (!AuthorizationAttributesMsService.httpClient) {
41
+ throw new Error('HTTP client is not initialized');
42
+ }
43
+ }
61
44
  }
62
45
 
63
46
  /**
64
- * Deletes specific attributes from a resource synchronously.
47
+ * Deletes a specific attribute from a resource synchronously.
65
48
  * @param accountId The account ID
66
49
  * @param resource Object with resourceType (string) and resourceId (number)
67
- * @param attributeKeys Array of attribute key strings to delete
68
- * @returns Promise<void>
50
+ * @param attributeKey Attribute key string to delete
51
+ * @returns Promise<ResourceAttributeDeleteOperation>
69
52
  */
70
53
  async deleteResourceAttributes(
71
54
  accountId: number,
72
55
  resource: Resource,
73
- attributeKeys: string[],
56
+ attributeKey: string,
74
57
  _appName?: string,
75
58
  _callerActionIdentifier?: string
76
- ): Promise<void> {
77
- ValidationUtils.validateResource(resource);
78
- ValidationUtils.validateStringArray(attributeKeys);
79
- return AuthorizationAttributesMsService.executeDeleteRequest(
59
+ ): Promise<ResourceAttributeDeleteOperation> {
60
+ const operation: ResourceAttributeDeleteOperation = await super.deleteResourceAttributes(
61
+ accountId,
62
+ resource,
63
+ attributeKey
64
+ );
65
+ await AuthorizationAttributesMsService.executeDeleteRequest(
80
66
  accountId,
81
67
  DELETE_RESOURCE_ATTRIBUTES_PATH,
82
68
  {
83
69
  resourceType: resource.type,
84
- resourceId: resource.id as number,
70
+ resourceId: resource.id,
85
71
  },
86
- attributeKeys,
72
+ [attributeKey],
87
73
  'resource',
88
- 'deleteResourceAttributesSync',
89
- { resource }
74
+ 'deleteResourceAttributesSync'
90
75
  );
76
+ return operation;
91
77
  }
92
78
 
93
79
  /**
94
- * Creates or updates entity attributes synchronously.
95
- * @param accountId The account ID
96
- * @param entityAttributeAssignments Array of EntityAttributeAssignment objects
97
- * @returns Promise<void>
98
- */
99
- async upsertEntityAttributes(
100
- accountId: number,
101
- entityAttributeAssignments: EntityAttributeAssignment[],
102
- _appName?: string,
103
- _callerActionIdentifier?: string
104
- ): Promise<void> {
105
- return AuthorizationAttributesMsService.executeUpsertRequest(
106
- accountId,
107
- entityAttributeAssignments,
108
- UPSERT_ENTITY_ATTRIBUTES_PATH,
109
- 'entityAttributeAssignments',
110
- EntityAttributeAssignment,
111
- 'entity',
112
- 'upsertEntityAttributesSync'
113
- );
114
- }
115
-
116
- /**
117
- * Deletes specific attributes from an entity synchronously.
80
+ * Deletes a specific attribute from an entity synchronously.
118
81
  * @param accountId The account ID
119
82
  * @param entityType The entity type
120
83
  * @param entityId The entity ID
121
- * @param attributeKeys Array of attribute key strings to delete
122
- * @returns Promise<void>
84
+ * @param attributeKey Attribute key string to delete
85
+ * @returns Promise<EntityAttributeDeleteOperation>
123
86
  */
124
87
  async deleteEntityAttributes(
125
88
  accountId: number,
126
89
  entityType: EntityType,
127
90
  entityId: number,
128
- attributeKeys: string[],
91
+ attributeKey: string,
129
92
  _appName?: string,
130
93
  _callerActionIdentifier?: string
131
- ): Promise<void> {
132
- if (!entityType || typeof entityType !== 'string' || entityType.trim() === '') {
133
- throw new ArgumentError(`entityType must be a non-empty string, got: ${entityType}`);
134
- }
135
- ValidationUtils.validateInteger(entityId);
136
-
137
- return AuthorizationAttributesMsService.executeDeleteRequest(
94
+ ): Promise<EntityAttributeDeleteOperation> {
95
+ const operation: EntityAttributeDeleteOperation = await super.deleteEntityAttributes(
96
+ accountId,
97
+ entityType,
98
+ entityId,
99
+ attributeKey
100
+ );
101
+ await AuthorizationAttributesMsService.executeDeleteRequest(
138
102
  accountId,
139
103
  DELETE_ENTITY_ATTRIBUTES_PATH,
140
104
  {
141
105
  entityType,
142
106
  entityId,
143
107
  },
144
- attributeKeys,
108
+ [attributeKey],
145
109
  'entity',
146
- 'deleteEntityAttributesSync',
147
- { entityType, entityId }
110
+ 'deleteEntityAttributesSync'
148
111
  );
112
+ return operation;
149
113
  }
150
114
 
151
115
  /**
152
- * Updates resource attributes (batch operations).
153
- * Note: MS service does not support batch operations directly.
154
- * This method processes operations sequentially using upsert/delete methods.
116
+ * Updates a resource attribute (single operation - upsert only).
155
117
  * @param accountId The account ID
156
118
  * @param appName App name (required for interface compatibility, but not used in MS service)
157
119
  * @param callerActionIdentifier Action identifier (required for interface compatibility, but not used in MS service)
158
- * @param resourceAttributeOperations Array of operations to perform
159
- * @returns Promise<ResourceAttributesOperation[]> Array of processed operations
120
+ * @param resourceAttributeOperation Operation to perform (must be UPSERT)
121
+ * @returns Promise<ResourceAttributeUpsertOperation> Processed operation
160
122
  */
161
123
  async updateResourceAttributes(
162
124
  accountId: number,
163
125
  _appName: string,
164
126
  _callerActionIdentifier: string,
165
- resourceAttributeOperations: ResourceAttributeOperation[]
166
- ): Promise<ResourceAttributeOperation[]> {
167
- const processedOperations: ResourceAttributeOperation[] = [];
168
-
169
- for (const operation of resourceAttributeOperations) {
170
- if (operation.operationType === AttributeOperation.UPSERT) {
171
- if (!operation.resourceId) {
172
- throw new ArgumentError('resourceId is required for upsert operation');
173
- }
174
- await this.upsertResourceAttributes(accountId, [
175
- new ResourceAttributeAssignment(
176
- operation.resourceId,
177
- operation.resourceType,
178
- operation.key,
179
- operation.value || ''
180
- ),
181
- ]);
182
- processedOperations.push(operation);
183
- } else if (operation.operationType === AttributeOperation.DELETE) {
184
- if (!operation.resourceId) {
185
- throw new ArgumentError('resourceId is required for delete operation');
186
- }
187
- await this.deleteResourceAttributes(
188
- accountId,
189
- {
190
- type: operation.resourceType,
191
- id: operation.resourceId,
192
- },
193
- [operation.key]
194
- );
195
- processedOperations.push(operation);
196
- }
197
- }
127
+ resourceAttributeOperation: ResourceAttributeUpsertOperation
128
+ ): Promise<ResourceAttributeUpsertOperation> {
129
+ await super.updateResourceAttributes(accountId, _appName, _callerActionIdentifier, resourceAttributeOperation);
130
+ await AuthorizationAttributesMsService.executeUpsertRequest(
131
+ accountId,
132
+ [
133
+ new ResourceAttributeAssignment(
134
+ resourceAttributeOperation.resourceId,
135
+ resourceAttributeOperation.resourceType,
136
+ resourceAttributeOperation.key,
137
+ resourceAttributeOperation.value
138
+ ),
139
+ ],
140
+ UPSERT_RESOURCE_ATTRIBUTES_PATH,
141
+ 'resourceAttributeAssignments',
142
+ 'resource',
143
+ 'updateResourceAttributesSync'
144
+ );
198
145
 
199
- return processedOperations;
146
+ return resourceAttributeOperation;
200
147
  }
201
148
 
202
149
  /**
203
- * Updates entity attributes (batch operations).
204
- * Note: MS service does not support batch operations directly.
205
- * This method processes operations sequentially using upsert/delete methods.
150
+ * Updates an entity attribute (single operation - upsert only).
206
151
  * @param accountId The account ID
207
152
  * @param appName App name (required for interface compatibility, but not used in MS service)
208
153
  * @param callerActionIdentifier Action identifier (required for interface compatibility, but not used in MS service)
209
- * @param entityAttributeOperations Array of operations to perform
210
- * @returns Promise<EntityAttributesOperation[]> Array of processed operations
154
+ * @param entityAttributeOperation Operation to perform (must be UPSERT)
155
+ * @returns Promise<EntityAttributeUpsertOperation> Processed operation
211
156
  */
212
157
  async updateEntityAttributes(
213
158
  accountId: number,
214
159
  _appName: string,
215
160
  _callerActionIdentifier: string,
216
- entityAttributeOperations: EntityAttributeOperation[]
217
- ): Promise<EntityAttributeOperation[]> {
218
- const processedOperations: EntityAttributeOperation[] = [];
219
- for (const operation of entityAttributeOperations) {
220
- if (operation.operationType === 'upsert') {
221
- await this.upsertEntityAttributes(accountId, [
222
- new EntityAttributeAssignment(operation.entityId, operation.entityType, operation.key, operation.value || ''),
223
- ]);
224
- processedOperations.push(operation);
225
- } else if (operation.operationType === 'delete') {
226
- await this.deleteEntityAttributes(accountId, operation.entityType, operation.entityId, [operation.key]);
227
- processedOperations.push(operation);
228
- }
229
- }
161
+ entityAttributeOperation: EntityAttributeUpsertOperation
162
+ ): Promise<EntityAttributeUpsertOperation> {
163
+ // Validate before processing
164
+ await super.updateEntityAttributes(accountId, _appName, _callerActionIdentifier, entityAttributeOperation);
165
+ await AuthorizationAttributesMsService.executeUpsertRequest(
166
+ accountId,
167
+ [
168
+ new EntityAttributeAssignment(
169
+ entityAttributeOperation.entityId,
170
+ entityAttributeOperation.entityType,
171
+ entityAttributeOperation.key,
172
+ entityAttributeOperation.value
173
+ ),
174
+ ],
175
+ UPSERT_ENTITY_ATTRIBUTES_PATH,
176
+ 'entityAttributeAssignments',
177
+ 'entity',
178
+ 'upsertEntityAttributesSync'
179
+ );
230
180
 
231
- return processedOperations;
181
+ return entityAttributeOperation;
232
182
  }
233
183
 
234
184
  /**
@@ -254,13 +204,8 @@ export class AuthorizationAttributesMsService implements AuthorizationAttributes
254
204
  pathParams: Record<string, string | number>,
255
205
  keys: string[],
256
206
  logPrefix: string,
257
- methodName: string,
258
- context: Record<string, any> = {}
207
+ methodName: string
259
208
  ): Promise<void> {
260
- // Validate inputs
261
- ValidationUtils.validateInteger(accountId);
262
- ValidationUtils.validateStringArray(keys);
263
-
264
209
  if (!keys.length) {
265
210
  logger.warn({ tag: this.LOG_TAG, accountId, ...pathParams }, `${methodName} called with empty keys array`);
266
211
  return;
@@ -306,7 +251,6 @@ export class AuthorizationAttributesMsService implements AuthorizationAttributes
306
251
  method: methodName,
307
252
  accountId,
308
253
  ...pathParams,
309
- ...context,
310
254
  error: err instanceof Error ? err.message : String(err),
311
255
  },
312
256
  `Failed in ${methodName}`
@@ -373,15 +317,9 @@ export class AuthorizationAttributesMsService implements AuthorizationAttributes
373
317
  assignments: T[],
374
318
  pathTemplate: string,
375
319
  requestBodyKey: 'resourceAttributeAssignments' | 'entityAttributeAssignments',
376
- assignmentClass: abstract new (...args: any[]) => T,
377
320
  logPrefix: string,
378
321
  methodName: string
379
322
  ): Promise<void> {
380
- ValidationUtils.validateInteger(accountId);
381
- ValidationUtils.validateArrayTypeOf(assignments, assignmentClass);
382
- if (!assignments.length) {
383
- return;
384
- }
385
323
  const assignmentDto = assignments.map(assignment => assignment.toDataTransferObject());
386
324
 
387
325
  const requestBody =
@@ -1,46 +1,48 @@
1
1
  import { AuthorizationAttributesMsService } from './authorization-attributes-ms-service';
2
2
  import { AuthorizationAttributesSnsService } from './authorization-attributes-sns-service';
3
- import { AuthorizationAttributesService as IAuthorizationAttributesService } from './types/authorization-attributes-service.interface';
3
+ import { BaseAuthorizationAttributesService as IAuthorizationAttributesService } from './base-authorization-attributes-service';
4
4
 
5
5
  /**
6
6
  * Main service class for managing resource and entity attributes.
7
- * Provides access to both direct (MS) and SNS operations.
7
+ * Provides access to both HTTP (direct microservice) and SNS (async messaging) operations.
8
8
  *
9
9
  * @example
10
10
  * const service = new AuthorizationAttributesService();
11
11
  *
12
- * // Use direct operations
13
- * await service.direct().upsertResourceAttributes(accountId, assignments);
12
+ * // Use HTTP operations (direct calls to microservice)
13
+ * await service.http().updateResourceAttributes(accountId, appName, actionId, operation);
14
14
  *
15
- * // Use SNS operations
16
- * await service.sns().upsertResourceAttributes(accountId, assignments, appName, actionId);
15
+ * // Use SNS operations (async messaging, then to microservice)
16
+ * await service.sns().updateResourceAttributes(accountId, appName, actionId, operation);
17
17
  * ```
18
18
  */
19
19
  export class AuthorizationAttributesService {
20
- private _directService: AuthorizationAttributesMsService | null = null;
21
- private _snsService: AuthorizationAttributesSnsService | null = null;
20
+ private httpService: AuthorizationAttributesMsService | null = null;
21
+ private snsService: AuthorizationAttributesSnsService | null = null;
22
22
 
23
23
  /**
24
- * Gets the direct (MS) service instance.
24
+ * Gets the HTTP service instance.
25
+ * Performs direct HTTP calls to the authorization microservice.
25
26
  * Initializes the service on first access (lazy initialization).
26
27
  * @returns IAuthorizationAttributesService instance
27
28
  */
28
- direct(): IAuthorizationAttributesService {
29
- if (this._directService === null) {
30
- this._directService = new AuthorizationAttributesMsService();
29
+ http(): IAuthorizationAttributesService {
30
+ if (this.httpService === null) {
31
+ this.httpService = new AuthorizationAttributesMsService();
31
32
  }
32
- return this._directService;
33
+ return this.httpService;
33
34
  }
34
35
 
35
36
  /**
36
37
  * Gets the SNS service instance.
38
+ * Sends operations via SNS messaging, which are then processed by the microservice asynchronously.
37
39
  * Initializes the service on first access (lazy initialization).
38
40
  * @returns IAuthorizationAttributesService instance
39
41
  */
40
42
  sns(): IAuthorizationAttributesService {
41
- if (this._snsService === null) {
42
- this._snsService = new AuthorizationAttributesSnsService();
43
+ if (this.snsService === null) {
44
+ this.snsService = new AuthorizationAttributesSnsService();
43
45
  }
44
- return this._snsService;
46
+ return this.snsService;
45
47
  }
46
48
  }