@mondaydotcomorg/monday-authorization 3.3.1 → 3.4.0-feature-bashanye-add-membership-create-delete-api-9ba3b16
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/README.md +127 -2
- package/dist/authorization-service.js +1 -1
- package/dist/clients/graph-api.d.ts.map +1 -1
- package/dist/clients/graph-api.js +1 -1
- package/dist/esm/authorization-service.mjs +1 -1
- package/dist/esm/clients/graph-api.d.ts.map +1 -1
- package/dist/esm/clients/graph-api.mjs +1 -1
- package/dist/esm/index.d.ts +10 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.mjs +15 -7
- package/dist/esm/memberships.d.ts +30 -0
- package/dist/esm/memberships.d.ts.map +1 -0
- package/dist/esm/memberships.mjs +98 -0
- package/dist/esm/metrics-service.d.ts +7 -4
- package/dist/esm/metrics-service.d.ts.map +1 -1
- package/dist/esm/metrics-service.mjs +34 -16
- package/dist/esm/types/memberships.d.ts +42 -0
- package/dist/esm/types/memberships.d.ts.map +1 -0
- package/dist/esm/types/memberships.mjs +1 -0
- package/dist/esm/utils/api-error-handler.d.ts +1 -1
- package/dist/esm/utils/api-error-handler.d.ts.map +1 -1
- package/dist/esm/utils/api-error-handler.mjs +4 -4
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/memberships.d.ts +30 -0
- package/dist/memberships.d.ts.map +1 -0
- package/dist/memberships.js +100 -0
- package/dist/metrics-service.d.ts +7 -4
- package/dist/metrics-service.d.ts.map +1 -1
- package/dist/metrics-service.js +34 -16
- package/dist/types/memberships.d.ts +42 -0
- package/dist/types/memberships.d.ts.map +1 -0
- package/dist/types/memberships.js +1 -0
- package/dist/utils/api-error-handler.d.ts +1 -1
- package/dist/utils/api-error-handler.d.ts.map +1 -1
- package/dist/utils/api-error-handler.js +4 -4
- package/package.json +1 -1
- package/src/authorization-service.ts +1 -1
- package/src/clients/graph-api.ts +1 -1
- package/src/index.ts +25 -15
- package/src/memberships.ts +111 -0
- package/src/metrics-service.ts +50 -18
- package/src/types/memberships.ts +47 -0
- package/src/utils/api-error-handler.ts +9 -5
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAqB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AAErC,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,sCAAsC,CAAC,EAAE,MAAM,CAAC;IAChD,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,iBA6BnD;AAED,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,8BAA8B,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5G,OAAO,EACL,WAAW,EACX,YAAY,EACZ,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAErH,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,19 +7,27 @@ const testKit_index = require('./testKit/index.js');
|
|
|
7
7
|
const authorizationMiddleware = require('./authorization-middleware.js');
|
|
8
8
|
const authorizationAttributesService = require('./authorization-attributes-service.js');
|
|
9
9
|
const rolesService = require('./roles-service.js');
|
|
10
|
+
const memberships = require('./memberships.js');
|
|
10
11
|
const types_roles = require('./types/roles.js');
|
|
11
12
|
|
|
12
13
|
async function init(options = {}) {
|
|
13
14
|
if (options.prometheus) {
|
|
14
15
|
prometheusService.setPrometheus(options.prometheus);
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
if (options.metrics) {
|
|
18
|
+
if (options.metrics.client) {
|
|
19
|
+
metricsService.initializeMetrics({ client: options.metrics.client });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const resolvedDisabled = options.metrics.disabled ?? ['test', 'development'].includes((process.env.NODE_ENV ?? '').toLowerCase());
|
|
23
|
+
metricsService.initializeMetrics({
|
|
24
|
+
serviceName: options.metrics.serviceName ?? process.env.APP_NAME ?? 'authorization-sdk',
|
|
25
|
+
host: options.metrics.host,
|
|
26
|
+
port: options.metrics.port,
|
|
27
|
+
disabled: resolvedDisabled,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
if (options.mondayFetchOptions) {
|
|
24
32
|
authorizationService.setRequestFetchOptions(options.mondayFetchOptions);
|
|
25
33
|
}
|
|
@@ -37,6 +45,7 @@ exports.getAuthorizationMiddleware = authorizationMiddleware.getAuthorizationMid
|
|
|
37
45
|
exports.skipAuthorizationMiddleware = authorizationMiddleware.skipAuthorizationMiddleware;
|
|
38
46
|
exports.AuthorizationAttributesService = authorizationAttributesService.AuthorizationAttributesService;
|
|
39
47
|
exports.RolesService = rolesService.RolesService;
|
|
48
|
+
exports.MembershipsService = memberships.MembershipsService;
|
|
40
49
|
Object.defineProperty(exports, 'RoleType', {
|
|
41
50
|
enumerable: true,
|
|
42
51
|
get: () => types_roles.RoleType
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { FetcherConfig, HttpClient } from '@mondaydotcomorg/trident-backend-api';
|
|
2
|
+
import { RecursivePartial } from '@mondaydotcomorg/monday-fetch-api';
|
|
3
|
+
import { MembershipCreateResponse, MembershipDeleteResponse, MembershipForCreate, MembershipForDelete } from './types/memberships';
|
|
4
|
+
export declare class MembershipsService {
|
|
5
|
+
private static API_PATHS;
|
|
6
|
+
private httpClient;
|
|
7
|
+
private fetchOptions;
|
|
8
|
+
/**
|
|
9
|
+
* Public constructor to create the AuthorizationAttributesService instance.
|
|
10
|
+
* @param httpClient The HTTP client to use for API requests, if not provided, the default HTTP client from Api will be used.
|
|
11
|
+
* @param fetchOptions The fetch options to use for API requests, if not provided, the default fetch options will be used.
|
|
12
|
+
*/
|
|
13
|
+
constructor(httpClient?: HttpClient, fetchOptions?: RecursivePartial<FetcherConfig>);
|
|
14
|
+
/**
|
|
15
|
+
* Upsert memberships synchronously, performing http call to the authorization MS to assign the given memberships.
|
|
16
|
+
* @param accountId
|
|
17
|
+
* @param memberships - Array of memberships to upsert
|
|
18
|
+
* @returns MembershipCreateResponse - The affected (created and updated) memberships.
|
|
19
|
+
*/
|
|
20
|
+
upsertMemberships(accountId: number, memberships: MembershipForCreate[]): Promise<MembershipCreateResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* Delete memberships synchronously, performing http call to the authorization MS to delete the given memberships.
|
|
23
|
+
* @param accountId
|
|
24
|
+
* @param resource - The resource (resourceType, resourceId) to delete the attributes for.
|
|
25
|
+
* @param attributeKeys - Array of attribute keys to delete for the resource.
|
|
26
|
+
* @returns ResourceAttributeResponse - The affected (deleted) resource attributes assignments in the `attributes` field.
|
|
27
|
+
*/
|
|
28
|
+
deleteMemberships(accountId: number, memberships: MembershipForDelete[]): Promise<MembershipDeleteResponse>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=memberships.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../src/memberships.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,aAAa,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAM3B,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,SAAS,CAGb;IACX,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAkC;IAEtD;;;;OAIG;gBACS,UAAU,CAAC,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,gBAAgB,CAAC,aAAa,CAAC;IAoBnF;;;;;OAKG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,wBAAwB,CAAC;IA0BjH;;;;;;OAMG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAyBlH"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
|
|
4
|
+
const utils_apiErrorHandler = require('./utils/api-error-handler.js');
|
|
5
|
+
const attributionsService = require('./attributions-service.js');
|
|
6
|
+
const constants = require('./constants.js');
|
|
7
|
+
|
|
8
|
+
class MembershipsService {
|
|
9
|
+
static API_PATHS = {
|
|
10
|
+
UPSERT_RESOURCE_ATTRIBUTES: '/memberships/{accountId}',
|
|
11
|
+
DELETE_RESOURCE_ATTRIBUTES: '/memberships/{accountId}',
|
|
12
|
+
};
|
|
13
|
+
httpClient;
|
|
14
|
+
fetchOptions;
|
|
15
|
+
/**
|
|
16
|
+
* Public constructor to create the AuthorizationAttributesService instance.
|
|
17
|
+
* @param httpClient The HTTP client to use for API requests, if not provided, the default HTTP client from Api will be used.
|
|
18
|
+
* @param fetchOptions The fetch options to use for API requests, if not provided, the default fetch options will be used.
|
|
19
|
+
*/
|
|
20
|
+
constructor(httpClient, fetchOptions) {
|
|
21
|
+
if (!httpClient) {
|
|
22
|
+
httpClient = tridentBackendApi.Api.getPart('httpClient');
|
|
23
|
+
if (!httpClient) {
|
|
24
|
+
throw new Error(constants.ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!fetchOptions) {
|
|
28
|
+
fetchOptions = constants.DEFAULT_FETCH_OPTIONS;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
fetchOptions = {
|
|
32
|
+
...constants.DEFAULT_FETCH_OPTIONS,
|
|
33
|
+
...fetchOptions,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
this.httpClient = httpClient;
|
|
37
|
+
this.fetchOptions = fetchOptions;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Upsert memberships synchronously, performing http call to the authorization MS to assign the given memberships.
|
|
41
|
+
* @param accountId
|
|
42
|
+
* @param memberships - Array of memberships to upsert
|
|
43
|
+
* @returns MembershipCreateResponse - The affected (created and updated) memberships.
|
|
44
|
+
*/
|
|
45
|
+
async upsertMemberships(accountId, memberships) {
|
|
46
|
+
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
47
|
+
try {
|
|
48
|
+
return await this.httpClient.fetch({
|
|
49
|
+
url: {
|
|
50
|
+
appName: constants.APP_NAME,
|
|
51
|
+
path: MembershipsService.API_PATHS.UPSERT_RESOURCE_ATTRIBUTES.replace('{accountId}', accountId.toString()),
|
|
52
|
+
},
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
query: {
|
|
55
|
+
useAStyleRoleId: 'true',
|
|
56
|
+
},
|
|
57
|
+
headers: {
|
|
58
|
+
'Content-Type': 'application/json',
|
|
59
|
+
...attributionHeaders,
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({ memberships }),
|
|
62
|
+
}, this.fetchOptions);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return utils_apiErrorHandler.handleApiError(err, 'authorization', 'upsertMemberships');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Delete memberships synchronously, performing http call to the authorization MS to delete the given memberships.
|
|
70
|
+
* @param accountId
|
|
71
|
+
* @param resource - The resource (resourceType, resourceId) to delete the attributes for.
|
|
72
|
+
* @param attributeKeys - Array of attribute keys to delete for the resource.
|
|
73
|
+
* @returns ResourceAttributeResponse - The affected (deleted) resource attributes assignments in the `attributes` field.
|
|
74
|
+
*/
|
|
75
|
+
async deleteMemberships(accountId, memberships) {
|
|
76
|
+
const attributionHeaders = attributionsService.getAttributionsFromApi();
|
|
77
|
+
try {
|
|
78
|
+
return await this.httpClient.fetch({
|
|
79
|
+
url: {
|
|
80
|
+
appName: constants.APP_NAME,
|
|
81
|
+
path: MembershipsService.API_PATHS.DELETE_RESOURCE_ATTRIBUTES.replace('{accountId}', accountId.toString()),
|
|
82
|
+
},
|
|
83
|
+
method: 'DELETE',
|
|
84
|
+
query: {
|
|
85
|
+
useAStyleRoleId: 'true',
|
|
86
|
+
},
|
|
87
|
+
headers: {
|
|
88
|
+
'Content-Type': 'application/json',
|
|
89
|
+
...attributionHeaders,
|
|
90
|
+
},
|
|
91
|
+
body: JSON.stringify({ memberships }),
|
|
92
|
+
}, this.fetchOptions);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
return utils_apiErrorHandler.handleApiError(err, 'authorization', 'deleteMemberships');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.MembershipsService = MembershipsService;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { Metric } from '@mondaydotcomorg/monday-observability-kit';
|
|
2
|
+
type ApiType = 'platform' | 'graph' | 'authorization';
|
|
3
|
+
export type MetricsClient = Pick<typeof Metric, 'distribution' | 'increment'>;
|
|
2
4
|
interface InitializeMetricsOptions {
|
|
3
|
-
|
|
5
|
+
client?: MetricsClient;
|
|
6
|
+
serviceName?: string;
|
|
4
7
|
host?: string;
|
|
5
8
|
port?: number;
|
|
6
9
|
disabled?: boolean;
|
|
7
10
|
}
|
|
8
11
|
export declare function initializeMetrics(options: InitializeMetricsOptions): void;
|
|
9
|
-
export declare function recordAuthorizationTiming(apiType: ApiType, duration: number): void;
|
|
10
|
-
export declare function recordAuthorizationError(apiType: ApiType, statusCode: number): void;
|
|
12
|
+
export declare function recordAuthorizationTiming(apiType: ApiType, duration: number, placement: string): void;
|
|
13
|
+
export declare function recordAuthorizationError(apiType: ApiType, statusCode: number, placement: string): void;
|
|
11
14
|
export {};
|
|
12
15
|
//# sourceMappingURL=metrics-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics-service.d.ts","sourceRoot":"","sources":["../src/metrics-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"metrics-service.d.ts","sourceRoot":"","sources":["../src/metrics-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGnE,KAAK,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,eAAe,CAAC;AAEtD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,MAAM,EAAE,cAAc,GAAG,WAAW,CAAC,CAAC;AAE9E,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAID,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAiCzE;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAoBrG;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAwBtG"}
|
package/dist/metrics-service.js
CHANGED
|
@@ -3,17 +3,21 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const mondayObservabilityKit = require('@mondaydotcomorg/monday-observability-kit');
|
|
4
4
|
const authorizationInternalService = require('./authorization-internal-service.js');
|
|
5
5
|
|
|
6
|
-
let
|
|
6
|
+
let metricsClient = null;
|
|
7
7
|
function initializeMetrics(options) {
|
|
8
|
-
if (
|
|
8
|
+
if (metricsClient) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (options.client) {
|
|
12
|
+
metricsClient = options.client;
|
|
9
13
|
return;
|
|
10
14
|
}
|
|
11
15
|
const { serviceName } = options;
|
|
12
16
|
if (!serviceName) {
|
|
13
|
-
authorizationInternalService.logger.warn({ tag: '
|
|
17
|
+
authorizationInternalService.logger.warn({ tag: 'monday-authorization-sdk' }, 'Metrics initialization skipped: serviceName is missing');
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
16
|
-
const resolvedHost = options.host ?? process.env.
|
|
20
|
+
const resolvedHost = options.host ?? process.env.HOST_IP ?? 'localhost';
|
|
17
21
|
const envPort = process.env.DOGSTATSD_PORT ? Number(process.env.DOGSTATSD_PORT) : undefined;
|
|
18
22
|
const resolvedPort = options.port ?? (Number.isFinite(envPort ?? NaN) ? envPort : undefined) ?? 8125;
|
|
19
23
|
const resolvedDisabled = options.disabled ?? ['test', 'development'].includes((process.env.NODE_ENV ?? '').toLowerCase());
|
|
@@ -24,32 +28,46 @@ function initializeMetrics(options) {
|
|
|
24
28
|
port: resolvedPort,
|
|
25
29
|
disabled: resolvedDisabled,
|
|
26
30
|
});
|
|
27
|
-
|
|
31
|
+
metricsClient = mondayObservabilityKit.Metric;
|
|
28
32
|
}
|
|
29
33
|
catch (error) {
|
|
30
|
-
authorizationInternalService.logger.warn({ tag: '
|
|
34
|
+
authorizationInternalService.logger.warn({ tag: 'monday-authorization-sdk', error }, 'Failed to initialize metrics');
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
|
-
function recordAuthorizationTiming(apiType, duration) {
|
|
34
|
-
if (!
|
|
37
|
+
function recordAuthorizationTiming(apiType, duration, placement) {
|
|
38
|
+
if (!metricsClient) {
|
|
35
39
|
return;
|
|
36
40
|
}
|
|
37
41
|
try {
|
|
38
|
-
|
|
42
|
+
metricsClient.distribution(`authorization.authorizationCheck.${apiType}.${placement}.duration`, duration);
|
|
39
43
|
}
|
|
40
|
-
catch {
|
|
41
|
-
|
|
44
|
+
catch (error) {
|
|
45
|
+
authorizationInternalService.logger.warn({
|
|
46
|
+
tag: 'monday-authorization-sdk',
|
|
47
|
+
metric: 'authorizationCheckDuration',
|
|
48
|
+
apiType,
|
|
49
|
+
placement,
|
|
50
|
+
duration,
|
|
51
|
+
error,
|
|
52
|
+
}, 'Failed to emit authorization timing metric');
|
|
42
53
|
}
|
|
43
54
|
}
|
|
44
|
-
function recordAuthorizationError(apiType, statusCode) {
|
|
45
|
-
if (!
|
|
55
|
+
function recordAuthorizationError(apiType, statusCode, placement) {
|
|
56
|
+
if (!metricsClient) {
|
|
46
57
|
return;
|
|
47
58
|
}
|
|
48
59
|
try {
|
|
49
|
-
|
|
60
|
+
metricsClient.increment(`authorization.authorizationCheck.${apiType}.${placement}.error`, { statusCode: String(statusCode) }, 1);
|
|
50
61
|
}
|
|
51
|
-
catch {
|
|
52
|
-
|
|
62
|
+
catch (error) {
|
|
63
|
+
authorizationInternalService.logger.warn({
|
|
64
|
+
tag: 'monday-authorization-sdk',
|
|
65
|
+
metric: 'authorizationCheckError',
|
|
66
|
+
apiType,
|
|
67
|
+
placement,
|
|
68
|
+
statusCode,
|
|
69
|
+
error,
|
|
70
|
+
}, 'Failed to emit authorization error metric');
|
|
53
71
|
}
|
|
54
72
|
}
|
|
55
73
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface MembershipForCreate {
|
|
2
|
+
entityId: number;
|
|
3
|
+
entityType: string;
|
|
4
|
+
resourceId: number;
|
|
5
|
+
resourceType: string;
|
|
6
|
+
roleId: number;
|
|
7
|
+
roleType?: string;
|
|
8
|
+
addedById: number;
|
|
9
|
+
}
|
|
10
|
+
export interface MembershipForDelete {
|
|
11
|
+
entityId?: number;
|
|
12
|
+
entityType: string;
|
|
13
|
+
resourceId?: number;
|
|
14
|
+
resourceType: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Membership {
|
|
17
|
+
id: number;
|
|
18
|
+
entityId: number;
|
|
19
|
+
entityType: string;
|
|
20
|
+
resourceId: number;
|
|
21
|
+
resourceType: string;
|
|
22
|
+
roleId: number;
|
|
23
|
+
roleType: string;
|
|
24
|
+
addedById: null | number | undefined;
|
|
25
|
+
hops: number;
|
|
26
|
+
isNewRecord: boolean;
|
|
27
|
+
previousValues: Partial<Membership>;
|
|
28
|
+
walVersion: number | null | undefined;
|
|
29
|
+
}
|
|
30
|
+
export interface MembershipCreateResponse {
|
|
31
|
+
memberships: Membership[];
|
|
32
|
+
}
|
|
33
|
+
export interface MembershipDeleteResponse {
|
|
34
|
+
memberships: Membership[];
|
|
35
|
+
}
|
|
36
|
+
export interface MembershipCreateRequest {
|
|
37
|
+
memberships: MembershipForCreate[];
|
|
38
|
+
}
|
|
39
|
+
export interface MembershipDeleteRequest {
|
|
40
|
+
memberships: MembershipForDelete[];
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=memberships.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memberships.d.ts","sourceRoot":"","sources":["../../src/types/memberships.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACpC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function handleApiError(err: unknown, apiType: 'platform' | 'graph', placement: string): never;
|
|
1
|
+
export declare function handleApiError(err: unknown, apiType: 'platform' | 'graph' | 'authorization', placement: string): never;
|
|
2
2
|
//# sourceMappingURL=api-error-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/api-error-handler.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,
|
|
1
|
+
{"version":3,"file":"api-error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/api-error-handler.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,UAAU,GAAG,OAAO,GAAG,eAAe,EAC/C,SAAS,EAAE,MAAM,GAChB,KAAK,CAgBP"}
|
|
@@ -6,13 +6,13 @@ const metricsService = require('../metrics-service.js');
|
|
|
6
6
|
|
|
7
7
|
function handleApiError(err, apiType, placement) {
|
|
8
8
|
if (err instanceof mondayFetchApi.HttpFetcherError) {
|
|
9
|
-
authorizationInternalService.logger.error({ tag: `${apiType}-api`, status: err.status, error: err.message }, `${apiType.charAt(0).toUpperCase() + apiType.slice(1)} API
|
|
10
|
-
metricsService.recordAuthorizationError(apiType, err.status);
|
|
9
|
+
authorizationInternalService.logger.error({ tag: `${apiType}-api`, status: err.status, error: err.message }, `${apiType.charAt(0).toUpperCase() + apiType.slice(1)} API ${placement} request failed`);
|
|
10
|
+
metricsService.recordAuthorizationError(apiType, err.status, placement);
|
|
11
11
|
authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, placement);
|
|
12
12
|
}
|
|
13
13
|
else {
|
|
14
|
-
authorizationInternalService.logger.error({ tag: `${apiType}-api`, error: err instanceof Error ? err.message : String(err) }, `${apiType.charAt(0).toUpperCase() + apiType.slice(1)} API
|
|
15
|
-
metricsService.recordAuthorizationError(apiType, 500);
|
|
14
|
+
authorizationInternalService.logger.error({ tag: `${apiType}-api`, error: err instanceof Error ? err.message : String(err) }, `${apiType.charAt(0).toUpperCase() + apiType.slice(1)} API ${placement} request failed`);
|
|
15
|
+
metricsService.recordAuthorizationError(apiType, 500, placement);
|
|
16
16
|
throw err;
|
|
17
17
|
}
|
|
18
18
|
}
|
package/package.json
CHANGED
|
@@ -213,7 +213,7 @@ export class AuthorizationService {
|
|
|
213
213
|
const { resourceType } = scopeToResource(scope);
|
|
214
214
|
const isAuthorized = obj.permit.can;
|
|
215
215
|
sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time);
|
|
216
|
-
recordAuthorizationTiming(apiType, time);
|
|
216
|
+
recordAuthorizationTiming(apiType, time, 'canActionInScopeMultiple');
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
return scopedActionResponseObjects;
|
package/src/clients/graph-api.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Api, HttpClient } from '@mondaydotcomorg/trident-backend-api';
|
|
2
|
+
import { signAuthorizationHeader } from '@mondaydotcomorg/monday-jwt';
|
|
2
3
|
import {
|
|
3
4
|
ScopedAction,
|
|
4
5
|
ScopedActionResponseObject,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
GraphPermissionReason,
|
|
18
19
|
} from '../types/graph-api.types';
|
|
19
20
|
import { scopeToResource } from '../utils/authorization.utils';
|
|
20
|
-
import { signAuthorizationHeader } from '@mondaydotcomorg/monday-jwt';
|
|
21
21
|
import { GRAPH_APP_NAME } from '../constants';
|
|
22
22
|
import { handleApiError } from '../utils/api-error-handler';
|
|
23
23
|
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { MondayFetchOptions } from '@mondaydotcomorg/monday-fetch';
|
|
2
2
|
import { setPrometheus } from './prometheus-service';
|
|
3
3
|
import { setIgniteClient, setRedisClient, setRequestFetchOptions } from './authorization-service';
|
|
4
|
-
import { initializeMetrics } from './metrics-service';
|
|
4
|
+
import { initializeMetrics, MetricsClient } from './metrics-service';
|
|
5
5
|
import * as TestKit from './testKit';
|
|
6
6
|
|
|
7
|
+
interface MetricsInitOptions {
|
|
8
|
+
client?: MetricsClient;
|
|
9
|
+
serviceName?: string;
|
|
10
|
+
host?: string;
|
|
11
|
+
port?: number;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
export interface InitOptions {
|
|
8
16
|
prometheus?: any;
|
|
9
17
|
mondayFetchOptions?: MondayFetchOptions;
|
|
10
18
|
redisClient?: any;
|
|
11
19
|
grantedFeatureRedisExpirationInSeconds?: number;
|
|
12
|
-
metrics?:
|
|
13
|
-
serviceName?: string;
|
|
14
|
-
host?: string;
|
|
15
|
-
port?: number;
|
|
16
|
-
disabled?: boolean;
|
|
17
|
-
};
|
|
20
|
+
metrics?: MetricsInitOptions;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export async function init(options: InitOptions = {}) {
|
|
@@ -22,14 +25,20 @@ export async function init(options: InitOptions = {}) {
|
|
|
22
25
|
setPrometheus(options.prometheus);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
options.metrics
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
if (options.metrics) {
|
|
29
|
+
if (options.metrics.client) {
|
|
30
|
+
initializeMetrics({ client: options.metrics.client });
|
|
31
|
+
} else {
|
|
32
|
+
const resolvedDisabled =
|
|
33
|
+
options.metrics.disabled ?? ['test', 'development'].includes((process.env.NODE_ENV ?? '').toLowerCase());
|
|
34
|
+
initializeMetrics({
|
|
35
|
+
serviceName: options.metrics.serviceName ?? process.env.APP_NAME ?? 'authorization-sdk',
|
|
36
|
+
host: options.metrics.host,
|
|
37
|
+
port: options.metrics.port,
|
|
38
|
+
disabled: resolvedDisabled,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
33
42
|
|
|
34
43
|
if (options.mondayFetchOptions) {
|
|
35
44
|
setRequestFetchOptions(options.mondayFetchOptions);
|
|
@@ -50,6 +59,7 @@ export {
|
|
|
50
59
|
export { AuthorizationService, AuthorizeResponse } from './authorization-service';
|
|
51
60
|
export { AuthorizationAttributesService } from './authorization-attributes-service';
|
|
52
61
|
export { RolesService } from './roles-service';
|
|
62
|
+
export { MembershipsService } from './memberships';
|
|
53
63
|
export { AuthorizationObject, Resource, BaseRequest, ResourceGetter, ContextGetter } from './types/general';
|
|
54
64
|
export {
|
|
55
65
|
Translation,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Api, FetcherConfig, HttpClient } from '@mondaydotcomorg/trident-backend-api';
|
|
2
|
+
import { RecursivePartial } from '@mondaydotcomorg/monday-fetch-api';
|
|
3
|
+
import {
|
|
4
|
+
MembershipCreateResponse,
|
|
5
|
+
MembershipDeleteResponse,
|
|
6
|
+
MembershipForCreate,
|
|
7
|
+
MembershipForDelete,
|
|
8
|
+
} from 'types/memberships';
|
|
9
|
+
import { handleApiError } from 'utils/api-error-handler';
|
|
10
|
+
import { getAttributionsFromApi } from './attributions-service';
|
|
11
|
+
|
|
12
|
+
import { APP_NAME, DEFAULT_FETCH_OPTIONS, ERROR_MESSAGES } from './constants';
|
|
13
|
+
|
|
14
|
+
export class MembershipsService {
|
|
15
|
+
private static API_PATHS = {
|
|
16
|
+
UPSERT_RESOURCE_ATTRIBUTES: '/memberships/{accountId}',
|
|
17
|
+
DELETE_RESOURCE_ATTRIBUTES: '/memberships/{accountId}',
|
|
18
|
+
} as const;
|
|
19
|
+
private httpClient: HttpClient;
|
|
20
|
+
private fetchOptions: RecursivePartial<FetcherConfig>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Public constructor to create the AuthorizationAttributesService instance.
|
|
24
|
+
* @param httpClient The HTTP client to use for API requests, if not provided, the default HTTP client from Api will be used.
|
|
25
|
+
* @param fetchOptions The fetch options to use for API requests, if not provided, the default fetch options will be used.
|
|
26
|
+
*/
|
|
27
|
+
constructor(httpClient?: HttpClient, fetchOptions?: RecursivePartial<FetcherConfig>) {
|
|
28
|
+
if (!httpClient) {
|
|
29
|
+
httpClient = Api.getPart('httpClient');
|
|
30
|
+
if (!httpClient) {
|
|
31
|
+
throw new Error(ERROR_MESSAGES.HTTP_CLIENT_NOT_INITIALIZED);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!fetchOptions) {
|
|
36
|
+
fetchOptions = DEFAULT_FETCH_OPTIONS;
|
|
37
|
+
} else {
|
|
38
|
+
fetchOptions = {
|
|
39
|
+
...DEFAULT_FETCH_OPTIONS,
|
|
40
|
+
...fetchOptions,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
this.httpClient = httpClient;
|
|
44
|
+
this.fetchOptions = fetchOptions;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Upsert memberships synchronously, performing http call to the authorization MS to assign the given memberships.
|
|
49
|
+
* @param accountId
|
|
50
|
+
* @param memberships - Array of memberships to upsert
|
|
51
|
+
* @returns MembershipCreateResponse - The affected (created and updated) memberships.
|
|
52
|
+
*/
|
|
53
|
+
async upsertMemberships(accountId: number, memberships: MembershipForCreate[]): Promise<MembershipCreateResponse> {
|
|
54
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
55
|
+
try {
|
|
56
|
+
return await this.httpClient.fetch<MembershipCreateResponse>(
|
|
57
|
+
{
|
|
58
|
+
url: {
|
|
59
|
+
appName: APP_NAME,
|
|
60
|
+
path: MembershipsService.API_PATHS.UPSERT_RESOURCE_ATTRIBUTES.replace('{accountId}', accountId.toString()),
|
|
61
|
+
},
|
|
62
|
+
method: 'PUT',
|
|
63
|
+
query: {
|
|
64
|
+
useAStyleRoleId: 'true',
|
|
65
|
+
},
|
|
66
|
+
headers: {
|
|
67
|
+
'Content-Type': 'application/json',
|
|
68
|
+
...attributionHeaders,
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify({ memberships }),
|
|
71
|
+
},
|
|
72
|
+
this.fetchOptions
|
|
73
|
+
);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return handleApiError(err, 'authorization', 'upsertMemberships');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Delete memberships synchronously, performing http call to the authorization MS to delete the given memberships.
|
|
81
|
+
* @param accountId
|
|
82
|
+
* @param resource - The resource (resourceType, resourceId) to delete the attributes for.
|
|
83
|
+
* @param attributeKeys - Array of attribute keys to delete for the resource.
|
|
84
|
+
* @returns ResourceAttributeResponse - The affected (deleted) resource attributes assignments in the `attributes` field.
|
|
85
|
+
*/
|
|
86
|
+
async deleteMemberships(accountId: number, memberships: MembershipForDelete[]): Promise<MembershipDeleteResponse> {
|
|
87
|
+
const attributionHeaders = getAttributionsFromApi();
|
|
88
|
+
try {
|
|
89
|
+
return await this.httpClient.fetch<MembershipDeleteResponse>(
|
|
90
|
+
{
|
|
91
|
+
url: {
|
|
92
|
+
appName: APP_NAME,
|
|
93
|
+
path: MembershipsService.API_PATHS.DELETE_RESOURCE_ATTRIBUTES.replace('{accountId}', accountId.toString()),
|
|
94
|
+
},
|
|
95
|
+
method: 'DELETE',
|
|
96
|
+
query: {
|
|
97
|
+
useAStyleRoleId: 'true',
|
|
98
|
+
},
|
|
99
|
+
headers: {
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
...attributionHeaders,
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify({ memberships }),
|
|
104
|
+
},
|
|
105
|
+
this.fetchOptions
|
|
106
|
+
);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
return handleApiError(err, 'authorization', 'deleteMemberships');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|