@mondaydotcomorg/monday-authorization 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-2d70b30 → 3.3.1-fix-use-standard-env-var-for-metric-server-host-7ed2241

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 (100) hide show
  1. package/README.md +19 -10
  2. package/dist/attributions-service.d.ts +3 -2
  3. package/dist/attributions-service.d.ts.map +1 -1
  4. package/dist/attributions-service.js +1 -0
  5. package/dist/authorization-internal-service.d.ts +1 -1
  6. package/dist/authorization-internal-service.d.ts.map +1 -1
  7. package/dist/authorization-service.d.ts +5 -0
  8. package/dist/authorization-service.d.ts.map +1 -1
  9. package/dist/authorization-service.js +30 -26
  10. package/dist/clients/graph-api.d.ts +28 -0
  11. package/dist/clients/graph-api.d.ts.map +1 -0
  12. package/dist/clients/{graph-api.client.js → graph-api.js} +48 -40
  13. package/dist/clients/platform-api.d.ts +26 -0
  14. package/dist/clients/platform-api.d.ts.map +1 -0
  15. package/dist/clients/{platform-api.client.js → platform-api.js} +20 -20
  16. package/dist/constants.d.ts +1 -0
  17. package/dist/constants.d.ts.map +1 -1
  18. package/dist/constants.js +2 -0
  19. package/dist/esm/attributions-service.d.ts +3 -2
  20. package/dist/esm/attributions-service.d.ts.map +1 -1
  21. package/dist/esm/attributions-service.mjs +1 -0
  22. package/dist/esm/authorization-internal-service.d.ts +1 -1
  23. package/dist/esm/authorization-internal-service.d.ts.map +1 -1
  24. package/dist/esm/authorization-service.d.ts +5 -0
  25. package/dist/esm/authorization-service.d.ts.map +1 -1
  26. package/dist/esm/authorization-service.mjs +31 -27
  27. package/dist/esm/clients/graph-api.d.ts +28 -0
  28. package/dist/esm/clients/graph-api.d.ts.map +1 -0
  29. package/dist/esm/clients/{graph-api.client.mjs → graph-api.mjs} +48 -40
  30. package/dist/esm/clients/platform-api.d.ts +26 -0
  31. package/dist/esm/clients/platform-api.d.ts.map +1 -0
  32. package/dist/esm/clients/{platform-api.client.mjs → platform-api.mjs} +21 -21
  33. package/dist/esm/constants.d.ts +1 -0
  34. package/dist/esm/constants.d.ts.map +1 -1
  35. package/dist/esm/constants.mjs +2 -1
  36. package/dist/esm/index.d.ts +6 -0
  37. package/dist/esm/index.d.ts.map +1 -1
  38. package/dist/esm/index.mjs +8 -0
  39. package/dist/esm/metrics-service.d.ts +12 -0
  40. package/dist/esm/metrics-service.d.ts.map +1 -0
  41. package/dist/esm/metrics-service.mjs +54 -0
  42. package/dist/esm/prometheus-service.d.ts +1 -3
  43. package/dist/esm/prometheus-service.d.ts.map +1 -1
  44. package/dist/esm/prometheus-service.mjs +5 -58
  45. package/dist/esm/types/graph-api.types.d.ts +8 -7
  46. package/dist/esm/types/graph-api.types.d.ts.map +1 -1
  47. package/dist/esm/types/scoped-actions-contracts.d.ts +10 -1
  48. package/dist/esm/types/scoped-actions-contracts.d.ts.map +1 -1
  49. package/dist/esm/types/scoped-actions-contracts.mjs +9 -0
  50. package/dist/esm/utils/api-error-handler.d.ts +2 -0
  51. package/dist/esm/utils/api-error-handler.d.ts.map +1 -0
  52. package/dist/esm/utils/api-error-handler.mjs +18 -0
  53. package/dist/index.d.ts +6 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +8 -0
  56. package/dist/metrics-service.d.ts +12 -0
  57. package/dist/metrics-service.d.ts.map +1 -0
  58. package/dist/metrics-service.js +58 -0
  59. package/dist/prometheus-service.d.ts +1 -3
  60. package/dist/prometheus-service.d.ts.map +1 -1
  61. package/dist/prometheus-service.js +4 -59
  62. package/dist/types/graph-api.types.d.ts +8 -7
  63. package/dist/types/graph-api.types.d.ts.map +1 -1
  64. package/dist/types/scoped-actions-contracts.d.ts +10 -1
  65. package/dist/types/scoped-actions-contracts.d.ts.map +1 -1
  66. package/dist/types/scoped-actions-contracts.js +9 -0
  67. package/dist/utils/api-error-handler.d.ts +2 -0
  68. package/dist/utils/api-error-handler.d.ts.map +1 -0
  69. package/dist/utils/api-error-handler.js +20 -0
  70. package/package.json +5 -2
  71. package/src/attributions-service.ts +93 -0
  72. package/src/authorization-attributes-service.ts +234 -0
  73. package/src/authorization-internal-service.ts +129 -0
  74. package/src/authorization-middleware.ts +51 -0
  75. package/src/authorization-service.ts +356 -0
  76. package/src/clients/graph-api.ts +170 -0
  77. package/src/clients/platform-api.ts +117 -0
  78. package/src/constants/sns.ts +5 -0
  79. package/src/constants.ts +23 -0
  80. package/src/index.ts +62 -0
  81. package/src/metrics-service.ts +67 -0
  82. package/src/prometheus-service.ts +51 -0
  83. package/src/roles-service.ts +125 -0
  84. package/src/testKit/index.ts +69 -0
  85. package/src/types/authorization-attributes-contracts.ts +33 -0
  86. package/src/types/express.ts +8 -0
  87. package/src/types/general.ts +32 -0
  88. package/src/types/graph-api.types.ts +25 -0
  89. package/src/types/roles.ts +42 -0
  90. package/src/types/scoped-actions-contracts.ts +57 -0
  91. package/src/utils/api-error-handler.ts +21 -0
  92. package/src/utils/authorization.utils.ts +47 -0
  93. package/dist/clients/graph-api.client.d.ts +0 -24
  94. package/dist/clients/graph-api.client.d.ts.map +0 -1
  95. package/dist/clients/platform-api.client.d.ts +0 -31
  96. package/dist/clients/platform-api.client.d.ts.map +0 -1
  97. package/dist/esm/clients/graph-api.client.d.ts +0 -24
  98. package/dist/esm/clients/graph-api.client.d.ts.map +0 -1
  99. package/dist/esm/clients/platform-api.client.d.ts +0 -31
  100. package/dist/esm/clients/platform-api.client.d.ts.map +0 -1
@@ -2,11 +2,12 @@ import { performance } from 'perf_hooks';
2
2
  import { Api } from '@mondaydotcomorg/trident-backend-api';
3
3
  import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
4
4
  import { getIgniteClient } from '@mondaydotcomorg/ignite-sdk';
5
- import { sendAuthorizationCheckResponseTimeMetric, incrementAuthorizationSuccess } from './prometheus-service.mjs';
5
+ import { sendAuthorizationCheckResponseTimeMetric } from './prometheus-service.mjs';
6
+ import { recordAuthorizationTiming } from './metrics-service.mjs';
6
7
  import { AuthorizationInternalService, logger } from './authorization-internal-service.mjs';
7
8
  import { getProfile, PlatformProfile, getAttributionsFromApi } from './attributions-service.mjs';
8
- import { GraphApiClient } from './clients/graph-api.client.mjs';
9
- import { PlatformApiClient } from './clients/platform-api.client.mjs';
9
+ import { GraphApi } from './clients/graph-api.mjs';
10
+ import { PlatformApi } from './clients/platform-api.mjs';
10
11
  import { scopeToResource } from './utils/authorization.utils.mjs';
11
12
 
12
13
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
@@ -19,6 +20,24 @@ function setRequestFetchOptions(customMondayFetchOptions) {
19
20
  AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
20
21
  }
21
22
  class AuthorizationService {
23
+ static get graphApi() {
24
+ if (!this._graphApi) {
25
+ this._graphApi = new GraphApi();
26
+ }
27
+ return this._graphApi;
28
+ }
29
+ static _graphApi;
30
+ static get platformApi() {
31
+ if (!this._platformApi) {
32
+ this._platformApi = new PlatformApi();
33
+ }
34
+ return this._platformApi;
35
+ }
36
+ static _platformApi;
37
+ static resetApiClients() {
38
+ this._graphApi = undefined;
39
+ this._platformApi = undefined;
40
+ }
22
41
  static redisClient;
23
42
  static grantedFeatureRedisExpirationInSeconds;
24
43
  static igniteClient;
@@ -84,38 +103,25 @@ class AuthorizationService {
84
103
  this.igniteClient.isReleased(PLATFORM_PROFILE_RELEASE_FF, { accountId, userId })) {
85
104
  return getProfile();
86
105
  }
87
- return PlatformProfile.INTERNAL;
106
+ return PlatformProfile.APP;
88
107
  }
89
108
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
90
109
  if (scopedActions.length === 0) {
91
110
  return [];
92
111
  }
93
112
  const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
94
- const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
95
113
  const startTime = performance.now();
96
114
  let scopedActionResponseObjects;
97
115
  let apiType;
98
116
  if (shouldNavigateToGraph) {
99
- try {
100
- scopedActionResponseObjects = await GraphApiClient.checkPermissions(internalAuthToken, scopedActions);
101
- apiType = 'graph';
102
- }
103
- catch (error) {
104
- const status = error instanceof HttpFetcherError ? error.status : undefined;
105
- logger.warn({
106
- tag: 'authorization-service',
107
- error: error instanceof Error ? error.message : String(error),
108
- accountId,
109
- userId,
110
- status,
111
- }, 'Graph API authorization failed');
112
- throw error;
113
- }
117
+ apiType = 'graph';
118
+ scopedActionResponseObjects = await this.graphApi.checkPermissions(accountId, userId, scopedActions);
114
119
  }
115
120
  else {
116
- const profile = this.getProfile(accountId, userId);
117
- scopedActionResponseObjects = await PlatformApiClient.checkPermissions(profile, internalAuthToken, userId, scopedActions);
118
121
  apiType = 'platform';
122
+ const profile = this.getProfile(accountId, userId);
123
+ const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
124
+ scopedActionResponseObjects = await this.platformApi.checkPermissions(profile, internalAuthToken, userId, scopedActions);
119
125
  }
120
126
  const endTime = performance.now();
121
127
  const time = endTime - startTime;
@@ -124,10 +130,8 @@ class AuthorizationService {
124
130
  const { action, scope } = obj.scopedAction;
125
131
  const { resourceType } = scopeToResource(scope);
126
132
  const isAuthorized = obj.permit.can;
127
- sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time, apiType);
128
- if (obj.permit.can) {
129
- incrementAuthorizationSuccess(resourceType, action, apiType);
130
- }
133
+ sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time);
134
+ recordAuthorizationTiming(apiType, time);
131
135
  }
132
136
  return scopedActionResponseObjects;
133
137
  }
@@ -184,7 +188,7 @@ class AuthorizationService {
184
188
  if (!isAuthorized) {
185
189
  unauthorizedObjects.push(authorizationObject);
186
190
  }
187
- sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
191
+ sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
188
192
  });
189
193
  if (unauthorizedObjects.length > 0) {
190
194
  logger.info({
@@ -0,0 +1,28 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { GraphIsAllowedResponse } from '../types/graph-api.types';
3
+ /**
4
+ * Client for handling Graph API authorization operations
5
+ */
6
+ export declare class GraphApi {
7
+ private readonly httpClient;
8
+ private readonly consumerAppName;
9
+ constructor();
10
+ /**
11
+ * Builds the request body for Graph API calls
12
+ */
13
+ private static buildRequestBody;
14
+ /**
15
+ * Fetches authorization data from the Graph API
16
+ */
17
+ fetchPermissions(authToken: string, scopedActions: ScopedAction[]): Promise<GraphIsAllowedResponse>;
18
+ /**
19
+ * Maps Graph API response to the expected format
20
+ */
21
+ private static mapResponse;
22
+ /**
23
+ * Performs a complete authorization check using the Graph API
24
+ */
25
+ checkPermissions(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
26
+ private static ensureGraphReason;
27
+ }
28
+ //# sourceMappingURL=graph-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-api.d.ts","sourceRoot":"","sources":["../../../src/clients/graph-api.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,0BAA0B,EAG3B,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEL,sBAAsB,EAMvB,MAAM,0BAA0B,CAAC;AASlC;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;;IAezC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAyB/B;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAgCzG;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAiC1B;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAMxC,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAWjC"}
@@ -1,16 +1,32 @@
1
1
  import { Api } from '@mondaydotcomorg/trident-backend-api';
2
- import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
3
2
  import { PermitTechnicalReason } from '../types/scoped-actions-contracts.mjs';
4
3
  import { AuthorizationInternalService } from '../authorization-internal-service.mjs';
5
4
  import { getAttributionsFromApi } from '../attributions-service.mjs';
6
5
  import { scopeToResource } from '../utils/authorization.utils.mjs';
7
- import { incrementAuthorizationError } from '../prometheus-service.mjs';
6
+ import { signAuthorizationHeader } from '@mondaydotcomorg/monday-jwt';
7
+ import { GRAPH_APP_NAME } from '../constants.mjs';
8
+ import { handleApiError } from '../utils/api-error-handler.mjs';
8
9
 
9
10
  const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
11
+ const APP_NAME_REQUIRED_ERROR = 'GraphApi: APP_NAME environment variable is required for Graph API authentication';
10
12
  /**
11
13
  * Client for handling Graph API authorization operations
12
14
  */
13
- class GraphApiClient {
15
+ class GraphApi {
16
+ httpClient;
17
+ consumerAppName;
18
+ constructor() {
19
+ const httpClient = Api.getPart('httpClient');
20
+ if (!httpClient) {
21
+ throw new Error('GraphApi: http client is not initialized');
22
+ }
23
+ const consumerAppName = process.env.APP_NAME?.trim();
24
+ if (!consumerAppName) {
25
+ throw new Error(APP_NAME_REQUIRED_ERROR);
26
+ }
27
+ this.httpClient = httpClient;
28
+ this.consumerAppName = consumerAppName;
29
+ }
14
30
  /**
15
31
  * Builds the request body for Graph API calls
16
32
  */
@@ -39,19 +55,18 @@ class GraphApiClient {
39
55
  /**
40
56
  * Fetches authorization data from the Graph API
41
57
  */
42
- static async fetchPermissions(internalAuthToken, scopedActions) {
43
- const httpClient = Api.getPart('httpClient');
58
+ async fetchPermissions(authToken, scopedActions) {
44
59
  const attributionHeaders = getAttributionsFromApi();
45
- const bodyPayload = this.buildRequestBody(scopedActions);
60
+ const bodyPayload = GraphApi.buildRequestBody(scopedActions);
46
61
  try {
47
- const response = await httpClient.fetch({
62
+ const response = await this.httpClient.fetch({
48
63
  url: {
49
- appName: 'authorization-graph',
64
+ appName: GRAPH_APP_NAME,
50
65
  path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
51
66
  },
52
67
  method: 'POST',
53
68
  headers: {
54
- Authorization: internalAuthToken,
69
+ Authorization: authToken,
55
70
  'Content-Type': 'application/json',
56
71
  ...attributionHeaders,
57
72
  },
@@ -63,13 +78,8 @@ class GraphApiClient {
63
78
  return response;
64
79
  }
65
80
  catch (err) {
66
- if (err instanceof HttpFetcherError) {
67
- AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
68
- if (scopedActions.length > 0) {
69
- incrementAuthorizationError(scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status, 'graph');
70
- }
71
- }
72
- throw err;
81
+ // handleApiError never returns (throws)
82
+ return handleApiError(err, 'graph', 'canActionInScopeMultiple');
73
83
  }
74
84
  }
75
85
  /**
@@ -81,41 +91,39 @@ class GraphApiClient {
81
91
  const { action, scope } = scopedAction;
82
92
  const { resourceType, resourceId } = scopeToResource(scope);
83
93
  const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
84
- const graphReason = permissionResult?.reason;
85
- let reasonKey;
86
- let additionalOptions = {};
87
- let technicalReason = PermitTechnicalReason.NO_REASON;
88
- if (typeof graphReason === 'string') {
89
- reasonKey = graphReason;
90
- }
91
- else if (graphReason && typeof graphReason === 'object') {
92
- reasonKey = graphReason.key ?? 'unknown';
93
- additionalOptions = graphReason.additionalOptions ?? {};
94
- if (graphReason.technicalReason !== undefined) {
95
- technicalReason = (graphReason.technicalReason ?? PermitTechnicalReason.NO_REASON);
96
- }
97
- }
98
- else {
99
- reasonKey = 'unknown';
100
- }
101
94
  const permit = {
102
95
  can: permissionResult?.can ?? false,
103
96
  reason: {
104
- key: reasonKey,
105
- ...additionalOptions,
97
+ key: 'unknown',
106
98
  },
107
- technicalReason,
99
+ technicalReason: PermitTechnicalReason.NO_REASON,
108
100
  };
101
+ if (permissionResult) {
102
+ const graphReason = GraphApi.ensureGraphReason(permissionResult.reason, { resourceType, resourceId, action });
103
+ permit.reason = {
104
+ key: graphReason.key,
105
+ ...(graphReason.additionalOptions ?? {}),
106
+ };
107
+ permit.technicalReason = (graphReason.technicalReason ??
108
+ PermitTechnicalReason.NO_REASON);
109
+ }
109
110
  return { scopedAction, permit };
110
111
  });
111
112
  }
112
113
  /**
113
114
  * Performs a complete authorization check using the Graph API
114
115
  */
115
- static async checkPermissions(internalAuthToken, scopedActions) {
116
- const response = await this.fetchPermissions(internalAuthToken, scopedActions);
117
- return this.mapResponse(scopedActions, response);
116
+ async checkPermissions(accountId, userId, scopedActions) {
117
+ const authToken = signAuthorizationHeader({ appName: this.consumerAppName, accountId, userId });
118
+ const response = await this.fetchPermissions(authToken, scopedActions);
119
+ return GraphApi.mapResponse(scopedActions, response);
120
+ }
121
+ static ensureGraphReason(reason, context) {
122
+ if (!reason || typeof reason !== 'object' || typeof reason.key !== 'string') {
123
+ throw new Error(`GraphApi: unexpected reason format for ${context.resourceType}/${context.resourceId}/${context.action}`);
124
+ }
125
+ return reason;
118
126
  }
119
127
  }
120
128
 
121
- export { GraphApiClient };
129
+ export { GraphApi };
@@ -0,0 +1,26 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { PlatformProfile } from '../attributions-service';
3
+ /**
4
+ * Client for handling Platform API authorization operations
5
+ */
6
+ export declare class PlatformApi {
7
+ private readonly httpClient;
8
+ constructor();
9
+ /**
10
+ * Builds the request payload for Platform API calls
11
+ */
12
+ private static buildRequestPayload;
13
+ /**
14
+ * Fetches authorization data from the Platform API
15
+ */
16
+ private fetchPermissions;
17
+ /**
18
+ * Maps Platform API response to the expected format
19
+ */
20
+ private static mapResponse;
21
+ /**
22
+ * Performs a complete authorization check using the Platform API
23
+ */
24
+ checkPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
25
+ }
26
+ //# sourceMappingURL=platform-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-api.d.ts","sourceRoot":"","sources":["../../../src/clients/platform-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAE7F,OAAO,EAA0B,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAelF;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;;IAUxC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC;;OAEG;YACW,gBAAgB;IAqC9B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAkB1B;;OAEG;IACG,gBAAgB,CACpB,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAKzC"}
@@ -1,15 +1,22 @@
1
1
  import { Api } from '@mondaydotcomorg/trident-backend-api';
2
- import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
3
2
  import { AuthorizationInternalService, logger } from '../authorization-internal-service.mjs';
4
3
  import { getAttributionsFromApi } from '../attributions-service.mjs';
5
- import { toSnakeCase, scopeToResource, toCamelCase } from '../utils/authorization.utils.mjs';
6
- import { incrementAuthorizationError } from '../prometheus-service.mjs';
4
+ import { toSnakeCase, toCamelCase } from '../utils/authorization.utils.mjs';
5
+ import { handleApiError } from '../utils/api-error-handler.mjs';
7
6
 
8
7
  const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
9
8
  /**
10
9
  * Client for handling Platform API authorization operations
11
10
  */
12
- class PlatformApiClient {
11
+ class PlatformApi {
12
+ httpClient;
13
+ constructor() {
14
+ const httpClient = Api.getPart('httpClient');
15
+ if (!httpClient) {
16
+ throw new Error('PlatformApi: http client is not initialized');
17
+ }
18
+ this.httpClient = httpClient;
19
+ }
13
20
  /**
14
21
  * Builds the request payload for Platform API calls
15
22
  */
@@ -22,11 +29,10 @@ class PlatformApiClient {
22
29
  /**
23
30
  * Fetches authorization data from the Platform API
24
31
  */
25
- static async fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload) {
32
+ async fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload) {
26
33
  const attributionHeaders = getAttributionsFromApi();
27
- const httpClient = Api.getPart('httpClient');
28
34
  try {
29
- const response = await httpClient.fetch({
35
+ const response = await this.httpClient.fetch({
30
36
  url: {
31
37
  appName: 'platform',
32
38
  path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
@@ -46,14 +52,8 @@ class PlatformApiClient {
46
52
  return response;
47
53
  }
48
54
  catch (err) {
49
- if (err instanceof HttpFetcherError) {
50
- AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
51
- if (scopedActionsPayload.length > 0) {
52
- const { resourceType } = scopeToResource(toCamelCase(scopedActionsPayload[0].scope));
53
- incrementAuthorizationError(resourceType, scopedActionsPayload[0].action, err.status, 'platform');
54
- }
55
- }
56
- throw err;
55
+ // handleApiError never returns (throws)
56
+ return handleApiError(err, 'platform', 'canActionInScopeMultiple');
57
57
  }
58
58
  }
59
59
  /**
@@ -61,8 +61,8 @@ class PlatformApiClient {
61
61
  */
62
62
  static mapResponse(response) {
63
63
  if (!response) {
64
- logger.error({ tag: 'platform-api-client', response }, 'PlatformApiClient: missing response');
65
- throw new Error('PlatformApiClient: missing response');
64
+ logger.error({ tag: 'platform-api', response }, 'PlatformApi: missing response');
65
+ throw new Error('PlatformApi: missing response');
66
66
  }
67
67
  return response.result.map(responseObject => {
68
68
  const { scopedAction, permit } = responseObject;
@@ -77,11 +77,11 @@ class PlatformApiClient {
77
77
  /**
78
78
  * Performs a complete authorization check using the Platform API
79
79
  */
80
- static async checkPermissions(profile, internalAuthToken, userId, scopedActions) {
81
- const scopedActionsPayload = this.buildRequestPayload(scopedActions);
80
+ async checkPermissions(profile, internalAuthToken, userId, scopedActions) {
81
+ const scopedActionsPayload = PlatformApi.buildRequestPayload(scopedActions);
82
82
  const platformResponse = await this.fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload);
83
- return this.mapResponse(platformResponse);
83
+ return PlatformApi.mapResponse(platformResponse);
84
84
  }
85
85
  }
86
86
 
87
- export { PlatformApiClient };
87
+ export { PlatformApi };
@@ -1,6 +1,7 @@
1
1
  import { RecursivePartial } from '@mondaydotcomorg/monday-fetch-api';
2
2
  import { FetcherConfig } from '@mondaydotcomorg/trident-backend-api';
3
3
  export declare const APP_NAME = "authorization";
4
+ export declare const GRAPH_APP_NAME = "authorization-graph";
4
5
  export declare const ERROR_MESSAGES: {
5
6
  readonly HTTP_CLIENT_NOT_INITIALIZED: "MondayAuthorization: HTTP client is not initialized";
6
7
  readonly REQUEST_FAILED: (method: string, status: number, reason: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAErE,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AAExC,eAAO,MAAM,cAAc;;sCAEA,MAAM,UAAU,MAAM,UAAU,MAAM;CAEvD,CAAC;AAEX,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAUjE,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAErE,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AACxC,eAAO,MAAM,cAAc,wBAAwB,CAAC;AAEpD,eAAO,MAAM,cAAc;;sCAEA,MAAM,UAAU,MAAM,UAAU,MAAM;CAEvD,CAAC;AAEX,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,CAAC,aAAa,CAUjE,CAAC"}
@@ -1,4 +1,5 @@
1
1
  const APP_NAME = 'authorization';
2
+ const GRAPH_APP_NAME = 'authorization-graph';
2
3
  const ERROR_MESSAGES = {
3
4
  HTTP_CLIENT_NOT_INITIALIZED: 'MondayAuthorization: HTTP client is not initialized',
4
5
  REQUEST_FAILED: (method, status, reason) => `MondayAuthorization: [${method}] request failed with status ${status} with reason: ${reason}`,
@@ -15,4 +16,4 @@ const DEFAULT_FETCH_OPTIONS = {
15
16
  },
16
17
  };
17
18
 
18
- export { APP_NAME, DEFAULT_FETCH_OPTIONS, ERROR_MESSAGES };
19
+ export { APP_NAME, DEFAULT_FETCH_OPTIONS, ERROR_MESSAGES, GRAPH_APP_NAME };
@@ -5,6 +5,12 @@ export interface InitOptions {
5
5
  mondayFetchOptions?: MondayFetchOptions;
6
6
  redisClient?: any;
7
7
  grantedFeatureRedisExpirationInSeconds?: number;
8
+ metrics?: {
9
+ serviceName?: string;
10
+ host?: string;
11
+ port?: number;
12
+ disabled?: boolean;
13
+ };
8
14
  }
9
15
  export declare function init(options?: InitOptions): Promise<void>;
10
16
  export { authorizationCheckMiddleware, getAuthorizationMiddleware, skipAuthorizationMiddleware, } from './authorization-middleware';
@@ -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;AAGnE,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AAErC,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;CACjD;AAED,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,iBAcnD;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,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAInE,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AAErC,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;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;CACH;AAED,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,iBAuBnD;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,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"}
@@ -1,6 +1,7 @@
1
1
  import { setPrometheus } from './prometheus-service.mjs';
2
2
  import { setRequestFetchOptions, setRedisClient, setIgniteClient } from './authorization-service.mjs';
3
3
  export { AuthorizationService } from './authorization-service.mjs';
4
+ import { initializeMetrics } from './metrics-service.mjs';
4
5
  import * as testKit_index from './testKit/index.mjs';
5
6
  export { testKit_index as TestKit };
6
7
  export { authorizationCheckMiddleware, getAuthorizationMiddleware, skipAuthorizationMiddleware } from './authorization-middleware.mjs';
@@ -12,6 +13,13 @@ async function init(options = {}) {
12
13
  if (options.prometheus) {
13
14
  setPrometheus(options.prometheus);
14
15
  }
16
+ const resolvedDisabled = options.metrics?.disabled ?? ['test', 'development'].includes((process.env.NODE_ENV ?? '').toLowerCase());
17
+ initializeMetrics({
18
+ serviceName: options.metrics?.serviceName ?? process.env.APP_NAME ?? 'authorization-sdk',
19
+ host: options.metrics?.host,
20
+ port: options.metrics?.port,
21
+ disabled: resolvedDisabled,
22
+ });
15
23
  if (options.mondayFetchOptions) {
16
24
  setRequestFetchOptions(options.mondayFetchOptions);
17
25
  }
@@ -0,0 +1,12 @@
1
+ type ApiType = 'platform' | 'graph';
2
+ interface InitializeMetricsOptions {
3
+ serviceName: string;
4
+ host?: string;
5
+ port?: number;
6
+ disabled?: boolean;
7
+ }
8
+ 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;
11
+ export {};
12
+ //# sourceMappingURL=metrics-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-service.d.ts","sourceRoot":"","sources":["../../src/metrics-service.ts"],"names":[],"mappings":"AAGA,KAAK,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEpC,UAAU,wBAAwB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,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,CA4BzE;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAUlF;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAUnF"}
@@ -0,0 +1,54 @@
1
+ import { Metric } from '@mondaydotcomorg/monday-observability-kit';
2
+ import { logger } from './authorization-internal-service.mjs';
3
+
4
+ let initialized = false;
5
+ function initializeMetrics(options) {
6
+ if (initialized) {
7
+ return;
8
+ }
9
+ const { serviceName } = options;
10
+ if (!serviceName) {
11
+ logger.warn({ tag: 'metrics-service' }, 'Metrics initialization skipped: serviceName is missing');
12
+ return;
13
+ }
14
+ const resolvedHost = options.host ?? process.env.HOST_IP ?? 'localhost';
15
+ const envPort = process.env.DOGSTATSD_PORT ? Number(process.env.DOGSTATSD_PORT) : undefined;
16
+ const resolvedPort = options.port ?? (Number.isFinite(envPort ?? NaN) ? envPort : undefined) ?? 8125;
17
+ const resolvedDisabled = options.disabled ?? ['test', 'development'].includes((process.env.NODE_ENV ?? '').toLowerCase());
18
+ try {
19
+ Metric.initialize({
20
+ serviceName,
21
+ host: resolvedHost,
22
+ port: resolvedPort,
23
+ disabled: resolvedDisabled,
24
+ });
25
+ initialized = true;
26
+ }
27
+ catch (error) {
28
+ logger.warn({ tag: 'metrics-service', error }, 'Failed to initialize metrics');
29
+ }
30
+ }
31
+ function recordAuthorizationTiming(apiType, duration) {
32
+ if (!initialized) {
33
+ return;
34
+ }
35
+ try {
36
+ Metric.distribution(`authorization.authorizationCheck.${apiType}.duration`, duration);
37
+ }
38
+ catch {
39
+ // ignore metric emission failures
40
+ }
41
+ }
42
+ function recordAuthorizationError(apiType, statusCode) {
43
+ if (!initialized) {
44
+ return;
45
+ }
46
+ try {
47
+ Metric.increment(`authorization.authorizationCheck.${apiType}.error`, { statusCode: String(statusCode) }, 1);
48
+ }
49
+ catch {
50
+ // ignore metric emission failures
51
+ }
52
+ }
53
+
54
+ export { initializeMetrics, recordAuthorizationError, recordAuthorizationTiming };
@@ -6,7 +6,5 @@ export declare const METRICS: {
6
6
  };
7
7
  export declare function setPrometheus(customPrometheus: any): void;
8
8
  export declare function getMetricsManager(): any;
9
- export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number, apiType?: 'platform' | 'graph'): void;
10
- export declare function incrementAuthorizationSuccess(resourceType: string, action: Action, apiType: 'platform' | 'graph'): void;
11
- export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number, apiType: 'platform' | 'graph'): void;
9
+ export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number): void;
12
10
  //# sourceMappingURL=prometheus-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAOzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAqB7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,UAAU,GAAG,OAAoB,QAW3C;AAcD,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,QAQhH;AAED,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,GAAG,OAAO,QAS9B"}
1
+ {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAa7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,QASb"}
@@ -1,7 +1,5 @@
1
1
  let prometheus = null;
2
2
  let authorizationCheckResponseTimeMetric = null;
3
- let authorizationSuccessMetric = null;
4
- let authorizationErrorMetric = null;
5
3
  const METRICS = {
6
4
  AUTHORIZATION_CHECK: 'authorization_check',
7
5
  AUTHORIZATION_CHECKS_PER_REQUEST: 'authorization_checks_per_request',
@@ -9,80 +7,29 @@ const METRICS = {
9
7
  };
10
8
  const authorizationCheckResponseTimeMetricConfig = {
11
9
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
12
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
10
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
13
11
  description: 'Authorization check response time summary',
14
12
  };
15
13
  function setPrometheus(customPrometheus) {
16
14
  prometheus = customPrometheus;
17
15
  if (!prometheus) {
18
- authorizationCheckResponseTimeMetric = null;
19
- authorizationSuccessMetric = null;
20
- authorizationErrorMetric = null;
21
16
  return;
22
17
  }
23
18
  const { METRICS_TYPES } = prometheus;
24
- const metricsManager = getMetricsManager();
25
- if (metricsManager) {
26
- authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
27
- initializeAdditionalMetrics();
28
- }
19
+ authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
29
20
  }
30
21
  function getMetricsManager() {
31
22
  return prometheus?.metricsManager;
32
23
  }
33
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
24
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
34
25
  try {
35
26
  if (authorizationCheckResponseTimeMetric) {
36
- authorizationCheckResponseTimeMetric
37
- .labels(resourceType, action, isAuthorized, responseStatus, apiType)
38
- .observe(time);
39
- }
40
- }
41
- catch (e) {
42
- // ignore
43
- }
44
- }
45
- const authorizationSuccessMetricConfig = {
46
- name: 'authorization_success_total',
47
- labels: ['resourceType', 'action', 'apiType'],
48
- description: 'Total number of successful authorization checks',
49
- };
50
- const authorizationErrorMetricConfig = {
51
- name: 'authorization_error_total',
52
- labels: ['resourceType', 'action', 'statusCode', 'apiType'],
53
- description: 'Total number of authorization errors',
54
- };
55
- function incrementAuthorizationSuccess(resourceType, action, apiType) {
56
- try {
57
- if (authorizationSuccessMetric) {
58
- authorizationSuccessMetric.labels(resourceType, action, apiType).inc();
27
+ authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
59
28
  }
60
29
  }
61
30
  catch (e) {
62
31
  // ignore
63
32
  }
64
33
  }
65
- function incrementAuthorizationError(resourceType, action, statusCode, apiType) {
66
- try {
67
- if (authorizationErrorMetric) {
68
- authorizationErrorMetric.labels(resourceType, action, statusCode, apiType).inc();
69
- }
70
- }
71
- catch (e) {
72
- // ignore
73
- }
74
- }
75
- // Initialize additional metrics when prometheus is set
76
- function initializeAdditionalMetrics() {
77
- if (!prometheus) {
78
- return;
79
- }
80
- const { METRICS_TYPES } = prometheus;
81
- const metricsManager = getMetricsManager();
82
- if (metricsManager) {
83
- authorizationSuccessMetric = metricsManager.addMetric(METRICS_TYPES.COUNTER, authorizationSuccessMetricConfig.name, authorizationSuccessMetricConfig.labels, authorizationSuccessMetricConfig.description);
84
- authorizationErrorMetric = metricsManager.addMetric(METRICS_TYPES.COUNTER, authorizationErrorMetricConfig.name, authorizationErrorMetricConfig.labels, authorizationErrorMetricConfig.description);
85
- }
86
- }
87
34
 
88
- export { METRICS, getMetricsManager, incrementAuthorizationError, incrementAuthorizationSuccess, sendAuthorizationCheckResponseTimeMetric, setPrometheus };
35
+ export { METRICS, getMetricsManager, sendAuthorizationCheckResponseTimeMetric, setPrometheus };