@mondaydotcomorg/monday-authorization 3.5.1 → 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 (124) 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/base-attribute-assignment.d.ts +18 -0
  15. package/dist/base-attribute-assignment.d.ts.map +1 -0
  16. package/dist/base-attribute-assignment.js +43 -0
  17. package/dist/constants/sns.d.ts +12 -2
  18. package/dist/constants/sns.d.ts.map +1 -1
  19. package/dist/constants/sns.js +22 -2
  20. package/dist/entity-attribute-assignment.d.ts +14 -0
  21. package/dist/entity-attribute-assignment.d.ts.map +1 -0
  22. package/dist/entity-attribute-assignment.js +24 -0
  23. package/dist/entity-attributes-constants.d.ts +7 -0
  24. package/dist/entity-attributes-constants.d.ts.map +1 -0
  25. package/dist/entity-attributes-constants.js +9 -0
  26. package/dist/errors/argument-error.d.ts +4 -0
  27. package/dist/errors/argument-error.d.ts.map +1 -0
  28. package/dist/errors/argument-error.js +11 -0
  29. package/dist/esm/authorization-attributes-ms-service.d.ts +95 -0
  30. package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -0
  31. package/dist/esm/authorization-attributes-ms-service.mjs +360 -0
  32. package/dist/esm/authorization-attributes-service.d.ts +26 -47
  33. package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
  34. package/dist/esm/authorization-attributes-service.mjs +33 -167
  35. package/dist/esm/authorization-attributes-sns-service.d.ts +91 -0
  36. package/dist/esm/authorization-attributes-sns-service.d.ts.map +1 -0
  37. package/dist/esm/authorization-attributes-sns-service.mjs +211 -0
  38. package/dist/esm/authorization-middleware.d.ts +2 -2
  39. package/dist/esm/authorization-middleware.d.ts.map +1 -1
  40. package/dist/esm/authorization-service.d.ts +3 -3
  41. package/dist/esm/authorization-service.d.ts.map +1 -1
  42. package/dist/esm/base-attribute-assignment.d.ts +18 -0
  43. package/dist/esm/base-attribute-assignment.d.ts.map +1 -0
  44. package/dist/esm/base-attribute-assignment.mjs +41 -0
  45. package/dist/esm/constants/sns.d.ts +12 -2
  46. package/dist/esm/constants/sns.d.ts.map +1 -1
  47. package/dist/esm/constants/sns.mjs +17 -3
  48. package/dist/esm/entity-attribute-assignment.d.ts +14 -0
  49. package/dist/esm/entity-attribute-assignment.d.ts.map +1 -0
  50. package/dist/esm/entity-attribute-assignment.mjs +22 -0
  51. package/dist/esm/entity-attributes-constants.d.ts +7 -0
  52. package/dist/esm/entity-attributes-constants.d.ts.map +1 -0
  53. package/dist/esm/entity-attributes-constants.mjs +7 -0
  54. package/dist/esm/errors/argument-error.d.ts +4 -0
  55. package/dist/esm/errors/argument-error.d.ts.map +1 -0
  56. package/dist/esm/errors/argument-error.mjs +9 -0
  57. package/dist/esm/index.d.ts +9 -0
  58. package/dist/esm/index.d.ts.map +1 -1
  59. package/dist/esm/index.mjs +7 -0
  60. package/dist/esm/prometheus-service.d.ts +1 -2
  61. package/dist/esm/prometheus-service.d.ts.map +1 -1
  62. package/dist/esm/resource-attribute-assignment.d.ts +24 -0
  63. package/dist/esm/resource-attribute-assignment.d.ts.map +1 -0
  64. package/dist/esm/resource-attribute-assignment.mjs +34 -0
  65. package/dist/esm/resource-attributes-constants.d.ts +15 -0
  66. package/dist/esm/resource-attributes-constants.d.ts.map +1 -0
  67. package/dist/esm/resource-attributes-constants.mjs +25 -0
  68. package/dist/esm/testKit/index.d.ts +4 -4
  69. package/dist/esm/testKit/index.d.ts.map +1 -1
  70. package/dist/esm/types/authorization-attributes-contracts.d.ts +27 -12
  71. package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
  72. package/dist/esm/types/authorization-attributes-contracts.mjs +6 -6
  73. package/dist/esm/types/authorization-attributes-service.interface.d.ts +57 -0
  74. package/dist/esm/types/authorization-attributes-service.interface.d.ts.map +1 -0
  75. package/dist/esm/types/authorization-attributes-service.interface.mjs +1 -0
  76. package/dist/esm/types/general.d.ts +1 -2
  77. package/dist/esm/types/general.d.ts.map +1 -1
  78. package/dist/esm/utils/validation.d.ts +45 -0
  79. package/dist/esm/utils/validation.d.ts.map +1 -0
  80. package/dist/esm/utils/validation.mjs +117 -0
  81. package/dist/index.d.ts +9 -0
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +15 -0
  84. package/dist/prometheus-service.d.ts +1 -2
  85. package/dist/prometheus-service.d.ts.map +1 -1
  86. package/dist/resource-attribute-assignment.d.ts +24 -0
  87. package/dist/resource-attribute-assignment.d.ts.map +1 -0
  88. package/dist/resource-attribute-assignment.js +36 -0
  89. package/dist/resource-attributes-constants.d.ts +15 -0
  90. package/dist/resource-attributes-constants.d.ts.map +1 -0
  91. package/dist/resource-attributes-constants.js +28 -0
  92. package/dist/testKit/index.d.ts +4 -4
  93. package/dist/testKit/index.d.ts.map +1 -1
  94. package/dist/types/authorization-attributes-contracts.d.ts +27 -12
  95. package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
  96. package/dist/types/authorization-attributes-contracts.js +5 -5
  97. package/dist/types/authorization-attributes-service.interface.d.ts +57 -0
  98. package/dist/types/authorization-attributes-service.interface.d.ts.map +1 -0
  99. package/dist/types/authorization-attributes-service.interface.js +1 -0
  100. package/dist/types/general.d.ts +1 -2
  101. package/dist/types/general.d.ts.map +1 -1
  102. package/dist/utils/validation.d.ts +45 -0
  103. package/dist/utils/validation.d.ts.map +1 -0
  104. package/dist/utils/validation.js +119 -0
  105. package/package.json +3 -2
  106. package/src/authorization-attributes-ms-service.ts +528 -0
  107. package/src/authorization-attributes-service.ts +35 -222
  108. package/src/authorization-attributes-sns-service.ts +312 -0
  109. package/src/authorization-middleware.ts +2 -2
  110. package/src/authorization-service.ts +4 -4
  111. package/src/base-attribute-assignment.ts +55 -0
  112. package/src/constants/sns.ts +19 -2
  113. package/src/entity-attribute-assignment.ts +21 -0
  114. package/src/entity-attributes-constants.ts +7 -0
  115. package/src/errors/argument-error.ts +7 -0
  116. package/src/index.ts +9 -0
  117. package/src/prometheus-service.ts +1 -2
  118. package/src/resource-attribute-assignment.ts +43 -0
  119. package/src/resource-attributes-constants.ts +35 -0
  120. package/src/testKit/index.ts +5 -5
  121. package/src/types/authorization-attributes-contracts.ts +36 -11
  122. package/src/types/authorization-attributes-service.interface.ts +100 -0
  123. package/src/types/general.ts +3 -2
  124. package/src/utils/validation.ts +114 -0
@@ -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[];
@@ -0,0 +1,114 @@
1
+ import { z } from 'zod';
2
+ import { ArgumentError } from '../errors/argument-error';
3
+
4
+ /**
5
+ * Utility class for common validation operations using Zod
6
+ */
7
+ export class ValidationUtils {
8
+ /**
9
+ * Validates that a value is an integer
10
+ * @param value The value to validate
11
+ * @param fieldName The name of the field for error messages
12
+ * @throws ArgumentError if value is not an integer
13
+ */
14
+ static validateInteger(value: any, fieldName: string): void {
15
+ const schema = z.number().int();
16
+ try {
17
+ schema.parse(value);
18
+ } catch (error) {
19
+ if (error instanceof z.ZodError) {
20
+ throw new ArgumentError(`${fieldName} must be an integer, got: ${value}`);
21
+ }
22
+ throw error;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Validates that a value is a non-empty string
28
+ * @param value The value to validate
29
+ * @param fieldName The name of the field for error messages
30
+ * @throws ArgumentError if value is not a string or is empty
31
+ */
32
+ static validateString(value: any, fieldName: string): void {
33
+ const schema = z.string().min(1);
34
+ try {
35
+ schema.parse(value);
36
+ } catch (error) {
37
+ if (error instanceof z.ZodError) {
38
+ if (typeof value !== 'string') {
39
+ throw new ArgumentError(`${fieldName} must be a string, got: ${typeof value}`);
40
+ }
41
+ throw new ArgumentError(`${fieldName} must be a non-empty string`);
42
+ }
43
+ throw error;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Validates that a value is an array and optionally checks minimum length
49
+ * @param value The value to validate
50
+ * @param fieldName The name of the field for error messages
51
+ * @param minLength Minimum required length (default: 0)
52
+ * @returns The validated array
53
+ * @throws ArgumentError if value is not an array or doesn't meet minimum length
54
+ */
55
+ static validateArray<T>(value: any, fieldName: string, minLength = 0): T[] {
56
+ const schema = z.array(z.any()).min(minLength);
57
+ try {
58
+ return schema.parse(value) as T[];
59
+ } catch (error) {
60
+ if (error instanceof z.ZodError) {
61
+ if (!Array.isArray(value)) {
62
+ throw new ArgumentError(`${fieldName} must be an array`);
63
+ }
64
+ throw new ArgumentError(`${fieldName} must have at least ${minLength} items`);
65
+ }
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Validates that a value is one of the allowed enum values
72
+ * @param value The value to validate
73
+ * @param validValues Array of valid values
74
+ * @param fieldName The name of the field for error messages
75
+ * @returns The validated value as the enum type
76
+ * @throws ArgumentError if value is not in validValues
77
+ */
78
+ static validateEnum<T extends string>(value: string, validValues: readonly T[], fieldName: string): T {
79
+ const schema = z.enum(validValues as [T, ...T[]]);
80
+ try {
81
+ return schema.parse(value) as T;
82
+ } catch (error) {
83
+ if (error instanceof z.ZodError) {
84
+ throw new ArgumentError(`${fieldName} must be one of [${validValues.join(', ')}], got: ${value}`);
85
+ }
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Validates that all items in an array are strings
92
+ * @param value Array to validate
93
+ * @param fieldName The name of the field for error messages
94
+ * @throws ArgumentError if any item is not a string
95
+ */
96
+ static validateStringArray(value: any[], fieldName: string): void {
97
+ const schema = z.array(z.string());
98
+ try {
99
+ schema.parse(value);
100
+ } catch (error) {
101
+ if (error instanceof z.ZodError) {
102
+ const zodError = error as z.ZodError;
103
+ const firstError = zodError.issues[0];
104
+ // Check if it's an array item validation error
105
+ if (firstError.path.length > 0 && typeof firstError.path[0] === 'number') {
106
+ const index = firstError.path[0];
107
+ throw new ArgumentError(`All ${fieldName} must be strings, but item at index ${index} is not`);
108
+ }
109
+ throw new ArgumentError(`${fieldName} must be an array`);
110
+ }
111
+ throw error;
112
+ }
113
+ }
114
+ }