@mondaydotcomorg/monday-authorization 3.5.3-feat-shaime-support-entity-attributes-in-authorization-sdk-ade64f6 → 3.7.0-feat-shaime-support-entity-attributes-4-49e1de0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authorization-attributes-ms-service.d.ts +6 -8
- package/dist/authorization-attributes-ms-service.d.ts.map +1 -1
- package/dist/authorization-attributes-ms-service.js +16 -95
- package/dist/authorization-attributes-service.d.ts +1 -2
- package/dist/authorization-attributes-service.d.ts.map +1 -1
- package/dist/authorization-attributes-service.js +0 -1
- package/dist/authorization-attributes-sns-service.d.ts +4 -3
- package/dist/authorization-attributes-sns-service.d.ts.map +1 -1
- package/dist/authorization-middleware.d.ts +2 -2
- package/dist/authorization-middleware.d.ts.map +1 -1
- package/dist/authorization-service.d.ts +3 -3
- package/dist/authorization-service.d.ts.map +1 -1
- package/dist/base-attribute-assignment.d.ts +2 -0
- package/dist/base-attribute-assignment.d.ts.map +1 -1
- package/dist/base-attribute-assignment.js +11 -18
- package/dist/entity-attribute-assignment.d.ts +6 -0
- package/dist/entity-attribute-assignment.d.ts.map +1 -1
- package/dist/entity-attribute-assignment.js +9 -1
- package/dist/entity-attributes-constants.d.ts +6 -6
- package/dist/entity-attributes-constants.d.ts.map +1 -1
- package/dist/entity-attributes-constants.js +7 -5
- package/dist/errors/argument-error.d.ts.map +1 -1
- package/dist/errors/argument-error.js +0 -1
- package/dist/esm/authorization-attributes-ms-service.d.ts +6 -8
- package/dist/esm/authorization-attributes-ms-service.d.ts.map +1 -1
- package/dist/esm/authorization-attributes-ms-service.mjs +16 -95
- package/dist/esm/authorization-attributes-service.d.ts +1 -2
- package/dist/esm/authorization-attributes-service.d.ts.map +1 -1
- package/dist/esm/authorization-attributes-service.mjs +0 -1
- package/dist/esm/authorization-attributes-sns-service.d.ts +4 -3
- package/dist/esm/authorization-attributes-sns-service.d.ts.map +1 -1
- package/dist/esm/authorization-middleware.d.ts +2 -2
- package/dist/esm/authorization-middleware.d.ts.map +1 -1
- package/dist/esm/authorization-service.d.ts +3 -3
- package/dist/esm/authorization-service.d.ts.map +1 -1
- package/dist/esm/base-attribute-assignment.d.ts +2 -0
- package/dist/esm/base-attribute-assignment.d.ts.map +1 -1
- package/dist/esm/base-attribute-assignment.mjs +7 -18
- package/dist/esm/entity-attribute-assignment.d.ts +6 -0
- package/dist/esm/entity-attribute-assignment.d.ts.map +1 -1
- package/dist/esm/entity-attribute-assignment.mjs +9 -1
- package/dist/esm/entity-attributes-constants.d.ts +6 -6
- package/dist/esm/entity-attributes-constants.d.ts.map +1 -1
- package/dist/esm/entity-attributes-constants.mjs +8 -6
- package/dist/esm/errors/argument-error.d.ts.map +1 -1
- package/dist/esm/errors/argument-error.mjs +0 -1
- package/dist/esm/index.d.ts +0 -9
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +0 -7
- package/dist/esm/prometheus-service.d.ts +2 -1
- package/dist/esm/prometheus-service.d.ts.map +1 -1
- package/dist/esm/resource-attribute-assignment.d.ts +7 -1
- package/dist/esm/resource-attribute-assignment.d.ts.map +1 -1
- package/dist/esm/resource-attribute-assignment.mjs +8 -0
- package/dist/esm/resource-attributes-constants.d.ts +12 -2
- package/dist/esm/resource-attributes-constants.d.ts.map +1 -1
- package/dist/esm/resource-attributes-constants.mjs +15 -12
- package/dist/esm/types/authorization-attributes-contracts.d.ts +1 -1
- package/dist/esm/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/dist/esm/types/authorization-attributes-service.interface.d.ts +4 -3
- package/dist/esm/types/authorization-attributes-service.interface.d.ts.map +1 -1
- package/dist/esm/types/general.d.ts +2 -1
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/utils/validation.d.ts +30 -30
- package/dist/esm/utils/validation.d.ts.map +1 -1
- package/dist/esm/utils/validation.mjs +121 -86
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -15
- package/dist/prometheus-service.d.ts +2 -1
- package/dist/prometheus-service.d.ts.map +1 -1
- package/dist/resource-attribute-assignment.d.ts +7 -1
- package/dist/resource-attribute-assignment.d.ts.map +1 -1
- package/dist/resource-attribute-assignment.js +8 -0
- package/dist/resource-attributes-constants.d.ts +12 -2
- package/dist/resource-attributes-constants.d.ts.map +1 -1
- package/dist/resource-attributes-constants.js +14 -11
- package/dist/types/authorization-attributes-contracts.d.ts +1 -1
- package/dist/types/authorization-attributes-contracts.d.ts.map +1 -1
- package/dist/types/authorization-attributes-service.interface.d.ts +4 -3
- package/dist/types/authorization-attributes-service.interface.d.ts.map +1 -1
- package/dist/types/general.d.ts +2 -1
- package/dist/types/general.d.ts.map +1 -1
- package/dist/utils/validation.d.ts +30 -30
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +125 -86
- package/package.json +4 -3
- package/src/authorization-attributes-ms-service.ts +23 -117
- package/src/authorization-attributes-service.ts +1 -2
- package/src/authorization-attributes-sns-service.ts +3 -3
- package/src/authorization-middleware.ts +2 -2
- package/src/authorization-service.ts +4 -4
- package/src/base-attribute-assignment.ts +14 -23
- package/src/entity-attribute-assignment.ts +10 -1
- package/src/entity-attributes-constants.ts +6 -6
- package/src/errors/argument-error.ts +0 -1
- package/src/index.ts +0 -9
- package/src/prometheus-service.ts +3 -1
- package/src/resource-attribute-assignment.ts +10 -1
- package/src/resource-attributes-constants.ts +13 -21
- package/src/types/authorization-attributes-contracts.ts +0 -2
- package/src/types/authorization-attributes-service.interface.ts +3 -3
- package/src/types/general.ts +2 -3
- package/src/utils/validation.ts +139 -82
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import onHeaders from 'on-headers';
|
|
2
2
|
import { AuthorizationInternalService } from './authorization-internal-service';
|
|
3
3
|
import { AuthorizationService, createAuthorizationParams } from './authorization-service';
|
|
4
|
-
import { BaseRequest, BaseResponse, Context, ContextGetter, ResourceGetter } from './types/general';
|
|
4
|
+
import { Action, BaseRequest, BaseResponse, Context, ContextGetter, ResourceGetter } from './types/general';
|
|
5
5
|
import type { NextFunction } from 'express';
|
|
6
6
|
|
|
7
7
|
// getAuthorizationMiddleware is duplicated in testKit/index.ts
|
|
8
8
|
// If you are making changes to this function, please make sure to update the other file as well
|
|
9
9
|
export function getAuthorizationMiddleware(
|
|
10
|
-
action:
|
|
10
|
+
action: Action,
|
|
11
11
|
resourceGetter: ResourceGetter,
|
|
12
12
|
contextGetter?: ContextGetter
|
|
13
13
|
) {
|
|
@@ -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 { AuthorizationObject, AuthorizationParams, Resource } from './types/general';
|
|
6
|
+
import { Action, 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:
|
|
77
|
+
action: Action
|
|
78
78
|
): Promise<AuthorizeResponse>;
|
|
79
79
|
|
|
80
80
|
static async isAuthorized(
|
|
@@ -223,7 +223,7 @@ export class AuthorizationService {
|
|
|
223
223
|
accountId: number,
|
|
224
224
|
userId: number,
|
|
225
225
|
resources: Resource[],
|
|
226
|
-
action:
|
|
226
|
+
action: Action
|
|
227
227
|
): Promise<AuthorizeResponse> {
|
|
228
228
|
const { authorizationObjects } = createAuthorizationParams(resources, action);
|
|
229
229
|
return this.isAuthorizedMultiple(accountId, userId, authorizationObjects);
|
|
@@ -338,7 +338,7 @@ export async function setIgniteClient() {
|
|
|
338
338
|
AuthorizationInternalService.setIgniteClient(igniteClient);
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
-
export function createAuthorizationParams(resources: Resource[], action:
|
|
341
|
+
export function createAuthorizationParams(resources: Resource[], action: Action): AuthorizationParams {
|
|
342
342
|
const params = {
|
|
343
343
|
authorizationObjects: resources.map((resource: Resource) => {
|
|
344
344
|
const authorizationObject: AuthorizationObject = {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ValidationUtils } from './utils/validation';
|
|
2
|
+
import isEqual from 'lodash/isEqual.js';
|
|
3
|
+
import { EntityAttributeAssignment, ResourceAttributeDelete } from './types/authorization-attributes-contracts';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Base class for attribute assignments (Resource or Entity)
|
|
@@ -19,21 +21,16 @@ export abstract class BaseAttributeAssignment<TId extends number, TType extends
|
|
|
19
21
|
idFieldName: string,
|
|
20
22
|
typeFieldName: string
|
|
21
23
|
) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// Validate attributeKey
|
|
29
|
-
ValidationUtils.validateString(attributeKey, 'attributeKey');
|
|
30
|
-
|
|
31
|
-
// Validate attributeValue
|
|
32
|
-
ValidationUtils.validateString(attributeValue, 'attributeValue');
|
|
24
|
+
const validated = ValidationUtils.validateAssignment<TType>(
|
|
25
|
+
{ id, type, attributeKey, attributeValue },
|
|
26
|
+
validTypes as readonly TType[],
|
|
27
|
+
{ id: idFieldName, type: typeFieldName }
|
|
28
|
+
);
|
|
33
29
|
|
|
34
|
-
this.id = id;
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
30
|
+
this.id = validated.id as TId;
|
|
31
|
+
this.type = validated.type as TType;
|
|
32
|
+
this.attributeKey = validated.attributeKey;
|
|
33
|
+
this.attributeValue = validated.attributeValue;
|
|
37
34
|
}
|
|
38
35
|
|
|
39
36
|
/**
|
|
@@ -42,14 +39,8 @@ export abstract class BaseAttributeAssignment<TId extends number, TType extends
|
|
|
42
39
|
* @returns true if all properties are equal
|
|
43
40
|
*/
|
|
44
41
|
equals(other: BaseAttributeAssignment<TId, TType>): boolean {
|
|
45
|
-
|
|
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
|
-
);
|
|
42
|
+
return isEqual(this, other);
|
|
54
43
|
}
|
|
44
|
+
|
|
45
|
+
abstract toDataTransferObject(): EntityAttributeAssignment | ResourceAttributeDelete;
|
|
55
46
|
}
|
|
@@ -6,10 +6,19 @@ export class EntityAttributeAssignment extends BaseAttributeAssignment<number, E
|
|
|
6
6
|
public readonly entityType: EntityType;
|
|
7
7
|
|
|
8
8
|
constructor(entityId: number, entityType: string, attributeKey: string, attributeValue: string) {
|
|
9
|
-
super(entityId, entityType, attributeKey, attributeValue,
|
|
9
|
+
super(entityId, entityType, attributeKey, attributeValue, ENTITY_TYPES, 'entityId', 'entityType');
|
|
10
10
|
this.entityId = entityId;
|
|
11
11
|
this.entityType = this.type;
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
toDataTransferObject() {
|
|
15
|
+
return {
|
|
16
|
+
entityId: this.entityId,
|
|
17
|
+
entityType: this.entityType,
|
|
18
|
+
key: this.attributeKey,
|
|
19
|
+
value: this.attributeValue,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
13
22
|
/**
|
|
14
23
|
* Compares two assignments for equality
|
|
15
24
|
* @param other Another EntityAttributeAssignment instance
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
export enum EntityType {
|
|
2
|
+
User = 'user',
|
|
3
|
+
Team = 'team',
|
|
4
|
+
Account = 'account',
|
|
5
|
+
}
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export const ENTITY_TYPES = Object.freeze(Object.values(EntityType));
|
package/src/index.ts
CHANGED
|
@@ -58,15 +58,6 @@ 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';
|
|
70
61
|
export { RolesService } from './roles-service';
|
|
71
62
|
export { MembershipsService } from './memberships';
|
|
72
63
|
export { AuthorizationObject, Resource, BaseRequest, ResourceGetter, ContextGetter } from './types/general';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Action } from './types/general';
|
|
2
|
+
|
|
1
3
|
let prometheus: any = null;
|
|
2
4
|
let authorizationCheckResponseTimeMetric: any = null;
|
|
3
5
|
|
|
@@ -34,7 +36,7 @@ export function getMetricsManager() {
|
|
|
34
36
|
|
|
35
37
|
export function sendAuthorizationCheckResponseTimeMetric(
|
|
36
38
|
resourceType: string,
|
|
37
|
-
action:
|
|
39
|
+
action: Action,
|
|
38
40
|
isAuthorized: boolean,
|
|
39
41
|
responseStatus: number,
|
|
40
42
|
time: number
|
|
@@ -5,7 +5,7 @@ export class ResourceAttributeAssignment extends BaseAttributeAssignment<number,
|
|
|
5
5
|
public readonly resourceId: number;
|
|
6
6
|
public readonly resourceType: ResourceType;
|
|
7
7
|
|
|
8
|
-
constructor(resourceId: number, resourceType:
|
|
8
|
+
constructor(resourceId: number, resourceType: ResourceType, attributeKey: string, attributeValue: string) {
|
|
9
9
|
super(
|
|
10
10
|
resourceId,
|
|
11
11
|
resourceType,
|
|
@@ -18,6 +18,15 @@ export class ResourceAttributeAssignment extends BaseAttributeAssignment<number,
|
|
|
18
18
|
this.resourceId = resourceId;
|
|
19
19
|
this.resourceType = this.type;
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
toDataTransferObject() {
|
|
23
|
+
return {
|
|
24
|
+
resourceId: this.resourceId,
|
|
25
|
+
resourceType: this.resourceType,
|
|
26
|
+
key: this.attributeKey,
|
|
27
|
+
value: this.attributeValue,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
21
30
|
/**
|
|
22
31
|
* Compares two assignments for equality
|
|
23
32
|
* @param other Another ResourceAttributeAssignment instance
|
|
@@ -11,25 +11,17 @@ export const RESOURCE_ATTRIBUTES_CONSTANTS = {
|
|
|
11
11
|
},
|
|
12
12
|
} as const;
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
export enum ResourceType {
|
|
15
|
+
Account = 'account',
|
|
16
|
+
AccountProduct = 'account_product',
|
|
17
|
+
Workspace = 'workspace',
|
|
18
|
+
Board = 'board',
|
|
19
|
+
Item = 'item',
|
|
20
|
+
Team = 'team',
|
|
21
|
+
Overview = 'overview',
|
|
22
|
+
Document = 'document',
|
|
23
|
+
Crm = 'crm',
|
|
24
|
+
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ACCOUNT_PRODUCT: 'account_product',
|
|
28
|
-
WORKSPACE: 'workspace',
|
|
29
|
-
BOARD: 'board',
|
|
30
|
-
ITEM: 'item',
|
|
31
|
-
TEAM: 'team',
|
|
32
|
-
OVERVIEW: 'overview',
|
|
33
|
-
DOCUMENT: 'document',
|
|
34
|
-
CRM: 'crm',
|
|
35
|
-
} as Record<string, ResourceType>;
|
|
26
|
+
// Define the array of strings and use 'as const' to make its contents literal types
|
|
27
|
+
export const RESOURCE_TYPES = Object.freeze(Object.values(ResourceType));
|
|
@@ -2,8 +2,6 @@ import { Resource } from './general';
|
|
|
2
2
|
import type { EntityType } from '../entity-attributes-constants';
|
|
3
3
|
import type { ResourceType } from '../resource-attributes-constants';
|
|
4
4
|
|
|
5
|
-
export type { EntityType, ResourceType };
|
|
6
|
-
|
|
7
5
|
interface AttributeAssignment {
|
|
8
6
|
key: string;
|
|
9
7
|
value: string;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ResourceAttributeAssignment as ResourceAttributeAssignmentContract,
|
|
3
3
|
EntityAttributeAssignment as EntityAttributeAssignmentContract,
|
|
4
|
-
EntityType,
|
|
5
4
|
ResourceAttributeOperation,
|
|
6
5
|
EntityAttributeOperation,
|
|
7
6
|
} from './authorization-attributes-contracts';
|
|
8
7
|
import { ResourceAttributeAssignment } from '../resource-attribute-assignment';
|
|
9
8
|
import { EntityAttributeAssignment } from '../entity-attribute-assignment';
|
|
10
9
|
import { Resource } from './general';
|
|
10
|
+
import { EntityType } from '../entity-attributes-constants';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Resource type compatible with both MS and SNS services
|
|
@@ -23,8 +23,8 @@ export interface CompatibleResource {
|
|
|
23
23
|
* Interface for authorization attributes operations.
|
|
24
24
|
* Both MS (direct) and SNS (async) services implement this interface.
|
|
25
25
|
*/
|
|
26
|
-
export interface
|
|
27
|
-
/**
|
|
26
|
+
export interface AuthorizationAttributesService {
|
|
27
|
+
/**authorization-attributes-service.ts
|
|
28
28
|
* Upserts resource attributes.
|
|
29
29
|
* For MS service: returns Promise<void>
|
|
30
30
|
* For SNS service: requires appName and callerActionIdentifier, returns Promise<ResourceAttributesOperation[]>
|
package/src/types/general.ts
CHANGED
|
@@ -5,17 +5,16 @@ export interface Resource {
|
|
|
5
5
|
type: string;
|
|
6
6
|
wrapperData?: object;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
export type Action = string;
|
|
9
9
|
export interface Context {
|
|
10
10
|
accountId: number;
|
|
11
11
|
userId: number;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
13
|
export interface AuthorizationObject {
|
|
15
14
|
resource_id?: Resource['id'];
|
|
16
15
|
resource_type: Resource['type'];
|
|
17
16
|
wrapper_data?: Resource['wrapperData'];
|
|
18
|
-
action:
|
|
17
|
+
action: Action;
|
|
19
18
|
}
|
|
20
19
|
export interface AuthorizationParams {
|
|
21
20
|
authorizationObjects: AuthorizationObject[];
|
package/src/utils/validation.ts
CHANGED
|
@@ -1,114 +1,171 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Ajv from 'ajv';
|
|
2
2
|
import { ArgumentError } from '../errors/argument-error';
|
|
3
|
+
import { Resource } from '../types/general';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* Utility class for common validation operations using
|
|
6
|
+
* Utility class for common validation operations using AJV
|
|
6
7
|
*/
|
|
7
8
|
export class ValidationUtils {
|
|
9
|
+
private static ajv = new Ajv({ allErrors: true });
|
|
8
10
|
/**
|
|
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
|
|
11
|
+
* Validates that a value is an integer. Throws ArgumentError with a descriptive message on failure.
|
|
13
12
|
*/
|
|
14
|
-
static validateInteger(value:
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
throw new ArgumentError(`${fieldName} must be an integer, got: ${value}`);
|
|
21
|
-
}
|
|
22
|
-
throw error;
|
|
13
|
+
static validateInteger(value: number): void {
|
|
14
|
+
const numberSchema = { type: 'number', multipleOf: 1 };
|
|
15
|
+
const validate = ValidationUtils.ajv.compile(numberSchema);
|
|
16
|
+
const isValid = validate(value);
|
|
17
|
+
if (!isValid) {
|
|
18
|
+
throw new ArgumentError(`Value must be an integer, got: ${value}`);
|
|
23
19
|
}
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
/**
|
|
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
|
|
23
|
+
* Validates that a value is a non-empty string. Throws ArgumentError on failure.
|
|
31
24
|
*/
|
|
32
|
-
static validateString(value:
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
throw error;
|
|
25
|
+
static validateString(value: string): void {
|
|
26
|
+
const non_empty_string_schema = {
|
|
27
|
+
type: 'string',
|
|
28
|
+
minLength: 1,
|
|
29
|
+
pattern: '\\S',
|
|
30
|
+
};
|
|
31
|
+
const validate = ValidationUtils.ajv.compile(non_empty_string_schema);
|
|
32
|
+
const isValid = validate(value);
|
|
33
|
+
if (!isValid) {
|
|
34
|
+
throw new ArgumentError(`Value must be a non-empty string, got: ${value}`);
|
|
44
35
|
}
|
|
45
36
|
}
|
|
46
37
|
|
|
47
38
|
/**
|
|
48
|
-
* Validates that a value is an array
|
|
49
|
-
*
|
|
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
|
|
39
|
+
* Validates that a value is an array of non-empty strings. Throws ArgumentError on failure.
|
|
40
|
+
* Allows empty arrays - caller should handle early return.
|
|
54
41
|
*/
|
|
55
|
-
static
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
42
|
+
static validateStringArray(value: string[]): void {
|
|
43
|
+
const string_array_schema = {
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
minLength: 1,
|
|
48
|
+
pattern: '\\S',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
const validateStringArray = ValidationUtils.ajv.compile(string_array_schema);
|
|
52
|
+
const isValid = validateStringArray(value);
|
|
53
|
+
if (!isValid) {
|
|
54
|
+
throw new ArgumentError(`Value must be an array of non-empty strings, got: ${value}`);
|
|
67
55
|
}
|
|
56
|
+
// Allow empty arrays to pass validation - caller should handle early return
|
|
57
|
+
// Non-empty arrays will be validated for string content above
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
/**
|
|
71
|
-
* Validates
|
|
72
|
-
*
|
|
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
|
|
61
|
+
* Validates an attribute assignment object using a single AJV schema.
|
|
62
|
+
* Preserves legacy error messages for each field.
|
|
77
63
|
*/
|
|
78
|
-
static
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
64
|
+
static validateAssignment<TType extends string>(
|
|
65
|
+
data: { id: any; type: string; attributeKey: any; attributeValue: any },
|
|
66
|
+
validTypes: readonly TType[],
|
|
67
|
+
fieldNames: { id: string; type: string }
|
|
68
|
+
): { id: number; type: TType; attributeKey: string; attributeValue: string } {
|
|
69
|
+
const schema = {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
id: { type: 'number', multipleOf: 1 },
|
|
73
|
+
type: { type: 'string', enum: validTypes as TType[] },
|
|
74
|
+
attributeKey: { type: 'string', minLength: 1 },
|
|
75
|
+
attributeValue: { type: 'string', minLength: 1 },
|
|
76
|
+
},
|
|
77
|
+
required: ['id', 'type', 'attributeKey', 'attributeValue'],
|
|
78
|
+
additionalProperties: false,
|
|
79
|
+
} as const;
|
|
80
|
+
|
|
81
|
+
const validate = this.ajv.compile(schema);
|
|
82
|
+
const valid = validate(data);
|
|
83
|
+
if (!valid) {
|
|
84
|
+
// Map to legacy error messages deterministically
|
|
85
|
+
const { id, type, attributeKey, attributeValue } = data;
|
|
86
|
+
|
|
87
|
+
// id must be integer
|
|
88
|
+
const isInteger = typeof id === 'number' && Number.isFinite(id) && Math.floor(id) === id;
|
|
89
|
+
if (!isInteger) {
|
|
90
|
+
throw new ArgumentError(`${fieldNames.id} must be an integer, got: ${id}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// type must be within enum
|
|
94
|
+
if (typeof type !== 'string' || !validTypes.includes(type as TType)) {
|
|
95
|
+
throw new ArgumentError(`${fieldNames.type} must be one of [${validTypes.join(', ')}], got: ${type}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// attributeKey
|
|
99
|
+
if (typeof attributeKey !== 'string') {
|
|
100
|
+
throw new ArgumentError(`attributeKey must be a string, got: ${typeof attributeKey}`);
|
|
101
|
+
}
|
|
102
|
+
if (!attributeKey) {
|
|
103
|
+
throw new ArgumentError('attributeKey must be a non-empty string');
|
|
85
104
|
}
|
|
86
|
-
|
|
105
|
+
|
|
106
|
+
// attributeValue
|
|
107
|
+
if (typeof attributeValue !== 'string') {
|
|
108
|
+
throw new ArgumentError(`attributeValue must be a string, got: ${typeof attributeValue}`);
|
|
109
|
+
}
|
|
110
|
+
if (!attributeValue) {
|
|
111
|
+
throw new ArgumentError('attributeValue must be a non-empty string');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Fallback
|
|
115
|
+
throw new ArgumentError('Invalid attribute assignment');
|
|
87
116
|
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
id: data.id as number,
|
|
120
|
+
type: data.type as TType,
|
|
121
|
+
attributeKey: data.attributeKey as string,
|
|
122
|
+
attributeValue: data.attributeValue as string,
|
|
123
|
+
};
|
|
88
124
|
}
|
|
89
125
|
|
|
90
126
|
/**
|
|
91
|
-
* Validates
|
|
92
|
-
*
|
|
93
|
-
* @param fieldName The name of the field for error messages
|
|
94
|
-
* @throws ArgumentError if any item is not a string
|
|
127
|
+
* Validates a Resource-like object shape: { id: number; type: string }.
|
|
128
|
+
* Throws ArgumentError with legacy-compatible messages.
|
|
95
129
|
*/
|
|
96
|
-
static
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
130
|
+
static validateResource(resource: Resource): void {
|
|
131
|
+
if (!resource || typeof resource !== 'object') {
|
|
132
|
+
throw new ArgumentError('resource must be an object');
|
|
133
|
+
}
|
|
134
|
+
const schema = {
|
|
135
|
+
type: 'object',
|
|
136
|
+
properties: {
|
|
137
|
+
id: { type: 'number', multipleOf: 1 },
|
|
138
|
+
type: { type: 'string', minLength: 1 },
|
|
139
|
+
wrapperData: { type: 'string' },
|
|
140
|
+
},
|
|
141
|
+
required: ['type', 'id'],
|
|
142
|
+
additionalProperties: false,
|
|
143
|
+
} as const;
|
|
144
|
+
const validate = this.ajv.compile(schema);
|
|
145
|
+
const isValid = validate(resource);
|
|
146
|
+
if (!isValid) {
|
|
147
|
+
throw new ArgumentError('Invalid resource');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static validateArrayTypeOf<T>(attributesMessages: T[], messageClass: abstract new (...args: any[]) => T): void {
|
|
152
|
+
const arraySchema = {
|
|
153
|
+
type: 'array',
|
|
154
|
+
};
|
|
155
|
+
const validateArray = ValidationUtils.ajv.compile(arraySchema);
|
|
156
|
+
const isArrayValid = validateArray(attributesMessages);
|
|
157
|
+
if (!isArrayValid) {
|
|
158
|
+
throw new ArgumentError(`attributesMessages must be an array`);
|
|
159
|
+
}
|
|
160
|
+
for (let i = 0; i < attributesMessages.length; i++) {
|
|
161
|
+
const item = attributesMessages[i];
|
|
162
|
+
if (!(item instanceof messageClass)) {
|
|
163
|
+
throw new ArgumentError(
|
|
164
|
+
`attributesMessages[${i}] must be an instance of ${messageClass.name}, got: ${
|
|
165
|
+
item?.constructor?.name || typeof item
|
|
166
|
+
}`
|
|
167
|
+
);
|
|
110
168
|
}
|
|
111
|
-
throw error;
|
|
112
169
|
}
|
|
113
170
|
}
|
|
114
171
|
}
|