@mondaydotcomorg/monday-authorization 3.2.3 → 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-8132586

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 CHANGED
@@ -137,6 +137,18 @@ const canActionInScopeMultipleResponse: ScopedActionResponseObject[] =
137
137
  * /
138
138
  ```
139
139
 
140
+ **Graph API Routing (v3.3.0+):**
141
+
142
+ Starting from version 3.3.0, `canActionInScope` and `canActionInScopeMultiple` can route authorization checks to the Graph API (`authorization-graph` service) instead of the Platform API. This routing is controlled by the Ignite feature flag `navigate-can-action-in-scope-to-graph`.
143
+
144
+ - **Feature Flag**: `navigate-can-action-in-scope-to-graph`
145
+ - **Default Behavior**: When the feature flag is disabled (default), the SDK routes to Platform API (backward compatible)
146
+ - **Graph Routing**: When enabled, authorization checks are routed to the Graph API endpoint `/permissions/is-allowed`
147
+ - **Automatic Fallback**: The SDK automatically falls back to Platform API if the feature flag is disabled
148
+ - **No Code Changes Required**: The routing is transparent - your code doesn't need to change. Simply upgrade to v3.3.0+ and the feature flag controls the routing behavior
149
+
150
+ The Graph API provides the same authorization results with improved performance and scalability. The feature flag allows for gradual rollout and easy rollback if needed.
151
+
140
152
  ### Authorization Attributes API
141
153
 
142
154
  Authorization attributes have 2 options to get called: sync (http request) and async (send to SNS and consumed asynchronously).
@@ -30,6 +30,14 @@ export declare class AuthorizationService {
30
30
  static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
31
31
  private static getProfile;
32
32
  static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
33
+ private static buildScopedActionsPayload;
34
+ private static scopeToResource;
35
+ private static buildGraphRequestBody;
36
+ private static fetchGraphIsAllowed;
37
+ private static mapGraphResponse;
38
+ private static fetchPlatformCanActions;
39
+ private static toCamelCase;
40
+ private static mapPlatformResponse;
33
41
  private static isAuthorizedSingular;
34
42
  private static isAuthorizedMultiple;
35
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAY1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAeD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBAkEnB,oBAAoB;mBAUpB,oBAAoB;CAmF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAuC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
@@ -20,9 +20,11 @@ const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
20
20
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
21
21
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
22
22
  const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
23
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
23
24
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
24
25
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
25
26
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
27
+ const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
26
28
  function setRequestFetchOptions(customMondayFetchOptions) {
27
29
  authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
28
30
  }
@@ -95,16 +97,128 @@ class AuthorizationService {
95
97
  return attributionsService.PlatformProfile.INTERNAL;
96
98
  }
97
99
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
98
- const profile = this.getProfile(accountId, userId);
100
+ const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
99
101
  const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
100
- const scopedActionsPayload = scopedActions.map(scopedAction => {
101
- return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
102
+ const startTime = perf_hooks.performance.now();
103
+ let scopedActionResponseObjects;
104
+ if (shouldNavigateToGraph) {
105
+ const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
106
+ scopedActionResponseObjects = this.mapGraphResponse(scopedActions, userId, response);
107
+ }
108
+ else {
109
+ const profile = this.getProfile(accountId, userId);
110
+ const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
111
+ const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
112
+ scopedActionResponseObjects = this.mapPlatformResponse(platformResponse);
113
+ }
114
+ const endTime = perf_hooks.performance.now();
115
+ const time = endTime - startTime;
116
+ const apiType = shouldNavigateToGraph ? 'graph' : 'platform';
117
+ for (const obj of scopedActionResponseObjects) {
118
+ const { action } = obj.scopedAction;
119
+ const resource_type = this.scopeToResource(obj.scopedAction.scope).resourceType;
120
+ const isAuthorized = obj.permit.can;
121
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(resource_type, action, isAuthorized, 200, time, apiType);
122
+ if (obj.permit.can) ;
123
+ }
124
+ return scopedActionResponseObjects;
125
+ }
126
+ static buildScopedActionsPayload(scopedActions) {
127
+ return scopedActions.map(scopedAction => {
128
+ return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) };
102
129
  });
130
+ }
131
+ static scopeToResource(scope) {
132
+ if ('workspaceId' in scope) {
133
+ return { resourceType: 'workspace', resourceId: scope.workspaceId };
134
+ }
135
+ if ('boardId' in scope) {
136
+ return { resourceType: 'board', resourceId: scope.boardId };
137
+ }
138
+ if ('pulseId' in scope) {
139
+ return { resourceType: 'pulse', resourceId: scope.pulseId };
140
+ }
141
+ if ('accountProductId' in scope) {
142
+ return { resourceType: 'account_product', resourceId: scope.accountProductId };
143
+ }
144
+ if ('accountId' in scope) {
145
+ return { resourceType: 'account', resourceId: scope.accountId };
146
+ }
147
+ throw new Error('Unsupported scope provided');
148
+ }
149
+ static buildGraphRequestBody(scopedActions) {
150
+ const resourcesAccumulator = {};
151
+ for (const { action, scope } of scopedActions) {
152
+ const { resourceType, resourceId } = this.scopeToResource(scope);
153
+ if (!resourcesAccumulator[resourceType]) {
154
+ resourcesAccumulator[resourceType] = {};
155
+ }
156
+ if (!resourcesAccumulator[resourceType][resourceId]) {
157
+ resourcesAccumulator[resourceType][resourceId] = new Set();
158
+ }
159
+ resourcesAccumulator[resourceType][resourceId].add(action);
160
+ }
161
+ const resourcesPayload = {};
162
+ for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
163
+ resourcesPayload[resourceType] = {};
164
+ for (const [idStr, actionsSet] of Object.entries(idMap)) {
165
+ const idNum = Number(idStr);
166
+ resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
167
+ }
168
+ }
169
+ return resourcesPayload;
170
+ }
171
+ static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
172
+ const httpClient = tridentBackendApi.Api.getPart('httpClient');
173
+ const attributionHeaders = attributionsService.getAttributionsFromApi();
174
+ const bodyPayload = this.buildGraphRequestBody(scopedActions);
175
+ try {
176
+ const response = await httpClient.fetch({
177
+ url: {
178
+ appName: 'authorization-graph',
179
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
180
+ },
181
+ method: 'POST',
182
+ headers: {
183
+ Authorization: internalAuthToken,
184
+ 'Content-Type': 'application/json',
185
+ ...attributionHeaders,
186
+ },
187
+ body: JSON.stringify(bodyPayload),
188
+ }, {
189
+ timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
190
+ retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
191
+ });
192
+ prometheusService.setGraphAvailability(true);
193
+ return response;
194
+ }
195
+ catch (err) {
196
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
197
+ authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
198
+ prometheusService.incrementAuthorizationError(this.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
199
+ }
200
+ throw err;
201
+ }
202
+ }
203
+ static mapGraphResponse(scopedActions, userId, graphResponse) {
204
+ const resources = graphResponse ?? {};
205
+ return scopedActions.map(scopedAction => {
206
+ const { action, scope } = scopedAction;
207
+ const { resourceType, resourceId } = this.scopeToResource(scope);
208
+ const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
209
+ const permit = {
210
+ can: permissionResult?.can ?? false,
211
+ reason: { key: permissionResult?.reason ?? 'unknown' },
212
+ technicalReason: 0,
213
+ };
214
+ return { scopedAction, permit };
215
+ });
216
+ }
217
+ static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
103
218
  const attributionHeaders = attributionsService.getAttributionsFromApi();
104
219
  const httpClient = tridentBackendApi.Api.getPart('httpClient');
105
- let response;
106
220
  try {
107
- response = await httpClient.fetch({
221
+ const response = await httpClient.fetch({
108
222
  url: {
109
223
  appName: 'platform',
110
224
  path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
@@ -116,40 +230,38 @@ class AuthorizationService {
116
230
  'Content-Type': 'application/json',
117
231
  ...attributionHeaders,
118
232
  },
119
- body: JSON.stringify({
120
- user_id: userId,
121
- scoped_actions: scopedActionsPayload,
122
- }),
233
+ body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
123
234
  }, {
124
235
  timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
125
236
  retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
126
237
  });
238
+ return response;
127
239
  }
128
240
  catch (err) {
129
241
  if (err instanceof mondayFetchApi.HttpFetcherError) {
130
242
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
243
+ prometheusService.incrementAuthorizationError(this.scopeToResource(this.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
131
244
  }
132
- else {
133
- throw err;
134
- }
135
- }
136
- function toCamelCase(obj) {
137
- return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
245
+ throw err;
138
246
  }
247
+ }
248
+ static toCamelCase(obj) {
249
+ return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
250
+ }
251
+ static mapPlatformResponse(response) {
139
252
  if (!response) {
140
253
  authorizationInternalService.logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
141
254
  throw new Error('AuthorizationService: missing response');
142
255
  }
143
- const scopedActionsResponseObjects = response.result.map(responseObject => {
256
+ return response.result.map(responseObject => {
144
257
  const { scopedAction, permit } = responseObject;
145
258
  const { scope } = scopedAction;
146
259
  return {
147
260
  ...responseObject,
148
- scopedAction: { ...scopedAction, scope: toCamelCase(scope) },
149
- permit: toCamelCase(permit),
261
+ scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
262
+ permit: this.toCamelCase(permit),
150
263
  };
151
264
  });
152
- return scopedActionsResponseObjects;
153
265
  }
154
266
  static async isAuthorizedSingular(accountId, userId, resources, action) {
155
267
  const { authorizationObjects } = createAuthorizationParams(resources, action);
@@ -185,7 +297,7 @@ class AuthorizationService {
185
297
  });
186
298
  }
187
299
  catch (err) {
188
- if (err instanceof httpClient.HttpFetcherError) {
300
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
189
301
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'isAuthorizedMultiple');
190
302
  }
191
303
  else {
@@ -204,7 +316,7 @@ class AuthorizationService {
204
316
  if (!isAuthorized) {
205
317
  unauthorizedObjects.push(authorizationObject);
206
318
  }
207
- prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
319
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
208
320
  });
209
321
  if (unauthorizedObjects.length > 0) {
210
322
  authorizationInternalService.logger.info({
@@ -30,6 +30,14 @@ export declare class AuthorizationService {
30
30
  static canActionInScope(accountId: number, userId: number, action: string, scope: ScopeOptions): Promise<ScopedActionPermit>;
31
31
  private static getProfile;
32
32
  static canActionInScopeMultiple(accountId: number, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
33
+ private static buildScopedActionsPayload;
34
+ private static scopeToResource;
35
+ private static buildGraphRequestBody;
36
+ private static fetchGraphIsAllowed;
37
+ private static mapGraphResponse;
38
+ private static fetchPlatformCanActions;
39
+ private static toCamelCase;
40
+ private static mapPlatformResponse;
33
41
  private static isAuthorizedSingular;
34
42
  private static isAuthorizedMultiple;
35
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAY1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAeD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;mBAkEnB,oBAAoB;mBAUpB,oBAAoB;CAmF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAuC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
@@ -5,16 +5,18 @@ import mapKeys from 'lodash/mapKeys.js';
5
5
  import { Api } from '@mondaydotcomorg/trident-backend-api';
6
6
  import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
7
7
  import { getIgniteClient } from '@mondaydotcomorg/ignite-sdk';
8
- import { sendAuthorizationCheckResponseTimeMetric } from './prometheus-service.mjs';
8
+ import { sendAuthorizationCheckResponseTimeMetric, setGraphAvailability, incrementAuthorizationError } from './prometheus-service.mjs';
9
9
  import { AuthorizationInternalService, logger } from './authorization-internal-service.mjs';
10
10
  import { getProfile, PlatformProfile, getAttributionsFromApi } from './attributions-service.mjs';
11
11
 
12
12
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
13
13
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
14
14
  const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
15
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
15
16
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
16
17
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
17
18
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
19
+ const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
18
20
  function setRequestFetchOptions(customMondayFetchOptions) {
19
21
  AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
20
22
  }
@@ -87,16 +89,128 @@ class AuthorizationService {
87
89
  return PlatformProfile.INTERNAL;
88
90
  }
89
91
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
90
- const profile = this.getProfile(accountId, userId);
92
+ const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
91
93
  const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
92
- const scopedActionsPayload = scopedActions.map(scopedAction => {
93
- return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) }; // for example: { workspaceId: 1 } => { workspace_id: 1 }
94
+ const startTime = performance.now();
95
+ let scopedActionResponseObjects;
96
+ if (shouldNavigateToGraph) {
97
+ const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
98
+ scopedActionResponseObjects = this.mapGraphResponse(scopedActions, userId, response);
99
+ }
100
+ else {
101
+ const profile = this.getProfile(accountId, userId);
102
+ const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
103
+ const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
104
+ scopedActionResponseObjects = this.mapPlatformResponse(platformResponse);
105
+ }
106
+ const endTime = performance.now();
107
+ const time = endTime - startTime;
108
+ const apiType = shouldNavigateToGraph ? 'graph' : 'platform';
109
+ for (const obj of scopedActionResponseObjects) {
110
+ const { action } = obj.scopedAction;
111
+ const resource_type = this.scopeToResource(obj.scopedAction.scope).resourceType;
112
+ const isAuthorized = obj.permit.can;
113
+ sendAuthorizationCheckResponseTimeMetric(resource_type, action, isAuthorized, 200, time, apiType);
114
+ if (obj.permit.can) ;
115
+ }
116
+ return scopedActionResponseObjects;
117
+ }
118
+ static buildScopedActionsPayload(scopedActions) {
119
+ return scopedActions.map(scopedAction => {
120
+ return { ...scopedAction, scope: mapKeys(scopedAction.scope, (_, key) => snakeCase(key)) };
94
121
  });
122
+ }
123
+ static scopeToResource(scope) {
124
+ if ('workspaceId' in scope) {
125
+ return { resourceType: 'workspace', resourceId: scope.workspaceId };
126
+ }
127
+ if ('boardId' in scope) {
128
+ return { resourceType: 'board', resourceId: scope.boardId };
129
+ }
130
+ if ('pulseId' in scope) {
131
+ return { resourceType: 'pulse', resourceId: scope.pulseId };
132
+ }
133
+ if ('accountProductId' in scope) {
134
+ return { resourceType: 'account_product', resourceId: scope.accountProductId };
135
+ }
136
+ if ('accountId' in scope) {
137
+ return { resourceType: 'account', resourceId: scope.accountId };
138
+ }
139
+ throw new Error('Unsupported scope provided');
140
+ }
141
+ static buildGraphRequestBody(scopedActions) {
142
+ const resourcesAccumulator = {};
143
+ for (const { action, scope } of scopedActions) {
144
+ const { resourceType, resourceId } = this.scopeToResource(scope);
145
+ if (!resourcesAccumulator[resourceType]) {
146
+ resourcesAccumulator[resourceType] = {};
147
+ }
148
+ if (!resourcesAccumulator[resourceType][resourceId]) {
149
+ resourcesAccumulator[resourceType][resourceId] = new Set();
150
+ }
151
+ resourcesAccumulator[resourceType][resourceId].add(action);
152
+ }
153
+ const resourcesPayload = {};
154
+ for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
155
+ resourcesPayload[resourceType] = {};
156
+ for (const [idStr, actionsSet] of Object.entries(idMap)) {
157
+ const idNum = Number(idStr);
158
+ resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
159
+ }
160
+ }
161
+ return resourcesPayload;
162
+ }
163
+ static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
164
+ const httpClient = Api.getPart('httpClient');
165
+ const attributionHeaders = getAttributionsFromApi();
166
+ const bodyPayload = this.buildGraphRequestBody(scopedActions);
167
+ try {
168
+ const response = await httpClient.fetch({
169
+ url: {
170
+ appName: 'authorization-graph',
171
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
172
+ },
173
+ method: 'POST',
174
+ headers: {
175
+ Authorization: internalAuthToken,
176
+ 'Content-Type': 'application/json',
177
+ ...attributionHeaders,
178
+ },
179
+ body: JSON.stringify(bodyPayload),
180
+ }, {
181
+ timeout: AuthorizationInternalService.getRequestTimeout(),
182
+ retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
183
+ });
184
+ setGraphAvailability(true);
185
+ return response;
186
+ }
187
+ catch (err) {
188
+ if (err instanceof HttpFetcherError) {
189
+ AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
190
+ incrementAuthorizationError(this.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
191
+ }
192
+ throw err;
193
+ }
194
+ }
195
+ static mapGraphResponse(scopedActions, userId, graphResponse) {
196
+ const resources = graphResponse ?? {};
197
+ return scopedActions.map(scopedAction => {
198
+ const { action, scope } = scopedAction;
199
+ const { resourceType, resourceId } = this.scopeToResource(scope);
200
+ const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
201
+ const permit = {
202
+ can: permissionResult?.can ?? false,
203
+ reason: { key: permissionResult?.reason ?? 'unknown' },
204
+ technicalReason: 0,
205
+ };
206
+ return { scopedAction, permit };
207
+ });
208
+ }
209
+ static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
95
210
  const attributionHeaders = getAttributionsFromApi();
96
211
  const httpClient = Api.getPart('httpClient');
97
- let response;
98
212
  try {
99
- response = await httpClient.fetch({
213
+ const response = await httpClient.fetch({
100
214
  url: {
101
215
  appName: 'platform',
102
216
  path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
@@ -108,40 +222,38 @@ class AuthorizationService {
108
222
  'Content-Type': 'application/json',
109
223
  ...attributionHeaders,
110
224
  },
111
- body: JSON.stringify({
112
- user_id: userId,
113
- scoped_actions: scopedActionsPayload,
114
- }),
225
+ body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
115
226
  }, {
116
227
  timeout: AuthorizationInternalService.getRequestTimeout(),
117
228
  retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
118
229
  });
230
+ return response;
119
231
  }
120
232
  catch (err) {
121
233
  if (err instanceof HttpFetcherError) {
122
234
  AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
235
+ incrementAuthorizationError(this.scopeToResource(this.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
123
236
  }
124
- else {
125
- throw err;
126
- }
127
- }
128
- function toCamelCase(obj) {
129
- return mapKeys(obj, (_, key) => camelCase(key));
237
+ throw err;
130
238
  }
239
+ }
240
+ static toCamelCase(obj) {
241
+ return mapKeys(obj, (_, key) => camelCase(key));
242
+ }
243
+ static mapPlatformResponse(response) {
131
244
  if (!response) {
132
245
  logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
133
246
  throw new Error('AuthorizationService: missing response');
134
247
  }
135
- const scopedActionsResponseObjects = response.result.map(responseObject => {
248
+ return response.result.map(responseObject => {
136
249
  const { scopedAction, permit } = responseObject;
137
250
  const { scope } = scopedAction;
138
251
  return {
139
252
  ...responseObject,
140
- scopedAction: { ...scopedAction, scope: toCamelCase(scope) },
141
- permit: toCamelCase(permit),
253
+ scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
254
+ permit: this.toCamelCase(permit),
142
255
  };
143
256
  });
144
- return scopedActionsResponseObjects;
145
257
  }
146
258
  static async isAuthorizedSingular(accountId, userId, resources, action) {
147
259
  const { authorizationObjects } = createAuthorizationParams(resources, action);
@@ -177,7 +289,7 @@ class AuthorizationService {
177
289
  });
178
290
  }
179
291
  catch (err) {
180
- if (err instanceof httpClient.HttpFetcherError) {
292
+ if (err instanceof HttpFetcherError) {
181
293
  AuthorizationInternalService.throwOnHttpError(err.status, 'isAuthorizedMultiple');
182
294
  }
183
295
  else {
@@ -196,7 +308,7 @@ class AuthorizationService {
196
308
  if (!isAuthorized) {
197
309
  unauthorizedObjects.push(authorizationObject);
198
310
  }
199
- sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
311
+ sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
200
312
  });
201
313
  if (unauthorizedObjects.length > 0) {
202
314
  logger.info({
@@ -6,5 +6,8 @@ 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): void;
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): void;
11
+ export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number): void;
12
+ export declare function setGraphAvailability(isAvailable: boolean): void;
10
13
  //# 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;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAU7C;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
+ {"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,QAiB7C;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;AAED,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAI;AAEtF,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAI;AAExG,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,QAAI"}
@@ -7,26 +7,38 @@ const METRICS = {
7
7
  };
8
8
  const authorizationCheckResponseTimeMetricConfig = {
9
9
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
10
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
10
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
11
11
  description: 'Authorization check response time summary',
12
12
  };
13
13
  function setPrometheus(customPrometheus) {
14
14
  prometheus = customPrometheus;
15
+ if (!prometheus) {
16
+ authorizationCheckResponseTimeMetric = null;
17
+ return;
18
+ }
15
19
  const { METRICS_TYPES } = prometheus;
16
- authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
20
+ const metricsManager = getMetricsManager();
21
+ if (metricsManager) {
22
+ authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
23
+ }
17
24
  }
18
25
  function getMetricsManager() {
19
26
  return prometheus?.metricsManager;
20
27
  }
21
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
28
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
22
29
  try {
23
30
  if (authorizationCheckResponseTimeMetric) {
24
- authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
31
+ authorizationCheckResponseTimeMetric
32
+ .labels(resourceType, action, isAuthorized, responseStatus, apiType)
33
+ .observe(time);
25
34
  }
26
35
  }
27
36
  catch (e) {
28
37
  // ignore
29
38
  }
30
39
  }
40
+ function incrementAuthorizationSuccess(resourceType, action) { }
41
+ function incrementAuthorizationError(resourceType, action, statusCode) { }
42
+ function setGraphAvailability(isAvailable) { }
31
43
 
32
- export { METRICS, getMetricsManager, sendAuthorizationCheckResponseTimeMetric, setPrometheus };
44
+ export { METRICS, getMetricsManager, incrementAuthorizationError, incrementAuthorizationSuccess, sendAuthorizationCheckResponseTimeMetric, setGraphAvailability, setPrometheus };
@@ -6,5 +6,8 @@ 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): void;
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): void;
11
+ export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number): void;
12
+ export declare function setGraphAvailability(isAvailable: boolean): void;
10
13
  //# 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;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAU7C;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
+ {"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,QAiB7C;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;AAED,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAI;AAEtF,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAI;AAExG,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,QAAI"}
@@ -9,29 +9,44 @@ const METRICS = {
9
9
  };
10
10
  const authorizationCheckResponseTimeMetricConfig = {
11
11
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
12
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
12
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
13
13
  description: 'Authorization check response time summary',
14
14
  };
15
15
  function setPrometheus(customPrometheus) {
16
16
  prometheus = customPrometheus;
17
+ if (!prometheus) {
18
+ authorizationCheckResponseTimeMetric = null;
19
+ return;
20
+ }
17
21
  const { METRICS_TYPES } = prometheus;
18
- authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
22
+ const metricsManager = getMetricsManager();
23
+ if (metricsManager) {
24
+ authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
25
+ }
19
26
  }
20
27
  function getMetricsManager() {
21
28
  return prometheus?.metricsManager;
22
29
  }
23
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
30
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
24
31
  try {
25
32
  if (authorizationCheckResponseTimeMetric) {
26
- authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
33
+ authorizationCheckResponseTimeMetric
34
+ .labels(resourceType, action, isAuthorized, responseStatus, apiType)
35
+ .observe(time);
27
36
  }
28
37
  }
29
38
  catch (e) {
30
39
  // ignore
31
40
  }
32
41
  }
42
+ function incrementAuthorizationSuccess(resourceType, action) { }
43
+ function incrementAuthorizationError(resourceType, action, statusCode) { }
44
+ function setGraphAvailability(isAvailable) { }
33
45
 
34
46
  exports.METRICS = METRICS;
35
47
  exports.getMetricsManager = getMetricsManager;
48
+ exports.incrementAuthorizationError = incrementAuthorizationError;
49
+ exports.incrementAuthorizationSuccess = incrementAuthorizationSuccess;
36
50
  exports.sendAuthorizationCheckResponseTimeMetric = sendAuthorizationCheckResponseTimeMetric;
51
+ exports.setGraphAvailability = setGraphAvailability;
37
52
  exports.setPrometheus = setPrometheus;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/monday-authorization",
3
- "version": "3.2.3",
3
+ "version": "3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-8132586",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",