@mondaydotcomorg/monday-authorization 3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b → 3.3.0-feat-add-graph-api-routing-support-2d70b30

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 (43) hide show
  1. package/README.md +29 -0
  2. package/dist/authorization-service.d.ts +0 -8
  3. package/dist/authorization-service.d.ts.map +1 -1
  4. package/dist/authorization-service.js +39 -151
  5. package/dist/clients/graph-api.client.d.ts +24 -0
  6. package/dist/clients/graph-api.client.d.ts.map +1 -0
  7. package/dist/clients/graph-api.client.js +123 -0
  8. package/dist/clients/platform-api.client.d.ts +31 -0
  9. package/dist/clients/platform-api.client.d.ts.map +1 -0
  10. package/dist/clients/platform-api.client.js +89 -0
  11. package/dist/esm/authorization-service.d.ts +0 -8
  12. package/dist/esm/authorization-service.d.ts.map +1 -1
  13. package/dist/esm/authorization-service.mjs +40 -146
  14. package/dist/esm/clients/graph-api.client.d.ts +24 -0
  15. package/dist/esm/clients/graph-api.client.d.ts.map +1 -0
  16. package/dist/esm/clients/graph-api.client.mjs +121 -0
  17. package/dist/esm/clients/platform-api.client.d.ts +31 -0
  18. package/dist/esm/clients/platform-api.client.d.ts.map +1 -0
  19. package/dist/esm/clients/platform-api.client.mjs +87 -0
  20. package/dist/esm/prometheus-service.d.ts +3 -1
  21. package/dist/esm/prometheus-service.d.ts.map +1 -1
  22. package/dist/esm/prometheus-service.mjs +61 -5
  23. package/dist/esm/testKit/index.d.ts.map +1 -1
  24. package/dist/esm/testKit/index.mjs +9 -7
  25. package/dist/esm/types/graph-api.types.d.ts +15 -0
  26. package/dist/esm/types/graph-api.types.d.ts.map +1 -0
  27. package/dist/esm/types/graph-api.types.mjs +1 -0
  28. package/dist/esm/utils/authorization.utils.d.ts +22 -0
  29. package/dist/esm/utils/authorization.utils.d.ts.map +1 -0
  30. package/dist/esm/utils/authorization.utils.mjs +39 -0
  31. package/dist/prometheus-service.d.ts +3 -1
  32. package/dist/prometheus-service.d.ts.map +1 -1
  33. package/dist/prometheus-service.js +62 -4
  34. package/dist/testKit/index.d.ts.map +1 -1
  35. package/dist/testKit/index.js +9 -7
  36. package/dist/types/graph-api.types.d.ts +15 -0
  37. package/dist/types/graph-api.types.d.ts.map +1 -0
  38. package/dist/types/graph-api.types.js +1 -0
  39. package/dist/utils/authorization.utils.d.ts +22 -0
  40. package/dist/utils/authorization.utils.d.ts.map +1 -0
  41. package/dist/utils/authorization.utils.js +49 -0
  42. package/package.json +2 -2
  43. package/CHANGELOG.md +0 -46
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).
@@ -244,6 +256,7 @@ const rolesResponse = await rolesService.getRoles(accountId, resourceTypes, styl
244
256
  ```
245
257
 
246
258
  **Parameters:**
259
+
247
260
  - `accountId` - The account ID
248
261
  - `resourceTypes` - Array of resource types to filter roles by (e.g., ['account', 'workspace'])
249
262
  - `style` - Deprecated, don't use it. the style of the roles to return, either 'A' or 'B' (default is 'A'). Note that basic role IDs are returned in A style and not B style.
@@ -273,6 +286,7 @@ const rolesResponse = await rolesService.createCustomRole(accountId, customRoles
273
286
  ```
274
287
 
275
288
  **Parameters:**
289
+
276
290
  - `accountId` - The account ID
277
291
  - `roles` - Array of `RoleCreateRequest` objects (cannot be empty)
278
292
 
@@ -298,6 +312,7 @@ const rolesResponse = await rolesService.updateCustomRole(accountId, updateReque
298
312
  ```
299
313
 
300
314
  **Parameters:**
315
+
301
316
  - `accountId` - The account ID
302
317
  - `updateRequests` - Array of `RoleUpdateRequest` objects
303
318
 
@@ -316,6 +331,7 @@ const rolesResponse = await rolesService.deleteCustomRole(accountId, roleIds);
316
331
  ```
317
332
 
318
333
  **Parameters:**
334
+
319
335
  - `accountId` - The account ID
320
336
  - `roleIds` - Array of custom role IDs to delete
321
337
 
@@ -376,3 +392,16 @@ interface RolesResponse {
376
392
  basicRoles?: BasicRole[];
377
393
  }
378
394
  ```
395
+
396
+ ## Development
397
+
398
+ ### Local Development and Testing
399
+
400
+ This package includes an `ignite-local-overrides.json` file for local development and testing only. It does **not** affect consumers of this package - they use their own Ignite configuration.
401
+
402
+ The file enables feature flags for testing:
403
+
404
+ - `sdk-platform-profiles`: Platform profile routing
405
+ - `navigate-can-action-in-scope-to-graph`: Graph API routing for `canActionInScope` methods
406
+
407
+ Modify this file for different local test scenarios, but remember changes only affect this package's development/testing.
@@ -30,14 +30,6 @@ 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;
41
33
  private static isAuthorizedSingular;
42
34
  private static isAuthorizedMultiple;
43
35
  }
@@ -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;AAc1C,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;AA6BD,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;IAsBxC,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;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,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":"AACA,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;AAMD,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;mBA6DnB,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"}
@@ -1,30 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const perf_hooks = require('perf_hooks');
4
- const snakeCase = require('lodash/snakeCase.js');
5
- const camelCase = require('lodash/camelCase.js');
6
- const mapKeys = require('lodash/mapKeys.js');
7
4
  const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
8
5
  const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
9
6
  const igniteSdk = require('@mondaydotcomorg/ignite-sdk');
10
7
  const prometheusService = require('./prometheus-service.js');
11
8
  const authorizationInternalService = require('./authorization-internal-service.js');
12
9
  const attributionsService = require('./attributions-service.js');
13
-
14
- const _interopDefault = e => e && e.__esModule ? e : { default: e };
15
-
16
- const snakeCase__default = /*#__PURE__*/_interopDefault(snakeCase);
17
- const camelCase__default = /*#__PURE__*/_interopDefault(camelCase);
18
- const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
10
+ const clients_graphApi_client = require('./clients/graph-api.client.js');
11
+ const clients_platformApi_client = require('./clients/platform-api.client.js');
12
+ const utils_authorization_utils = require('./utils/authorization.utils.js');
19
13
 
20
14
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
21
15
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
22
- const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
23
16
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
24
17
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
25
18
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
26
19
  const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
27
- const GRAPH_IS_ALLOWED_PATH = '/permissions/is-allowed';
28
20
  function setRequestFetchOptions(customMondayFetchOptions) {
29
21
  authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
30
22
  }
@@ -97,153 +89,49 @@ class AuthorizationService {
97
89
  return attributionsService.PlatformProfile.INTERNAL;
98
90
  }
99
91
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
92
+ if (scopedActions.length === 0) {
93
+ return [];
94
+ }
100
95
  const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
101
96
  const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
97
+ const startTime = perf_hooks.performance.now();
98
+ let scopedActionResponseObjects;
99
+ let apiType;
102
100
  if (shouldNavigateToGraph) {
103
- const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
104
- return this.mapGraphResponse(scopedActions, userId, response);
105
- }
106
- const profile = this.getProfile(accountId, userId);
107
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
108
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
109
- return this.mapPlatformResponse(platformResponse);
110
- }
111
- static buildScopedActionsPayload(scopedActions) {
112
- return scopedActions.map(scopedAction => {
113
- return { ...scopedAction, scope: mapKeys__default.default(scopedAction.scope, (_, key) => snakeCase__default.default(key)) };
114
- });
115
- }
116
- static scopeToResource(scope) {
117
- if ('workspaceId' in scope) {
118
- return { resourceType: 'workspace', resourceId: scope.workspaceId };
119
- }
120
- if ('boardId' in scope) {
121
- return { resourceType: 'board', resourceId: scope.boardId };
122
- }
123
- if ('pulseId' in scope) {
124
- return { resourceType: 'pulse', resourceId: scope.pulseId };
125
- }
126
- if ('accountProductId' in scope) {
127
- return { resourceType: 'account_product', resourceId: scope.accountProductId };
128
- }
129
- if ('accountId' in scope) {
130
- return { resourceType: 'account', resourceId: scope.accountId };
131
- }
132
- throw new Error('Unsupported scope provided');
133
- }
134
- static buildGraphRequestBody(scopedActions) {
135
- const resourcesAccumulator = {};
136
- for (const { action, scope } of scopedActions) {
137
- const { resourceType, resourceId } = this.scopeToResource(scope);
138
- if (!resourcesAccumulator[resourceType]) {
139
- resourcesAccumulator[resourceType] = {};
101
+ try {
102
+ scopedActionResponseObjects = await clients_graphApi_client.GraphApiClient.checkPermissions(internalAuthToken, scopedActions);
103
+ apiType = 'graph';
140
104
  }
141
- if (!resourcesAccumulator[resourceType][resourceId]) {
142
- resourcesAccumulator[resourceType][resourceId] = new Set();
105
+ catch (error) {
106
+ const status = error instanceof mondayFetchApi.HttpFetcherError ? error.status : undefined;
107
+ authorizationInternalService.logger.warn({
108
+ tag: 'authorization-service',
109
+ error: error instanceof Error ? error.message : String(error),
110
+ accountId,
111
+ userId,
112
+ status,
113
+ }, 'Graph API authorization failed');
114
+ throw error;
143
115
  }
144
- resourcesAccumulator[resourceType][resourceId].add(action);
145
116
  }
146
- const resourcesPayload = {};
147
- for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
148
- resourcesPayload[resourceType] = {};
149
- for (const [idStr, actionsSet] of Object.entries(idMap)) {
150
- const idNum = Number(idStr);
151
- resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
152
- }
153
- }
154
- return resourcesPayload;
155
- }
156
- static async fetchGraphIsAllowed(internalAuthToken, scopedActions) {
157
- const httpClient = tridentBackendApi.Api.getPart('httpClient');
158
- const attributionHeaders = attributionsService.getAttributionsFromApi();
159
- const bodyPayload = this.buildGraphRequestBody(scopedActions);
160
- try {
161
- const response = await httpClient.fetch({
162
- url: {
163
- appName: 'authorization-graph',
164
- path: GRAPH_IS_ALLOWED_PATH,
165
- },
166
- method: 'POST',
167
- headers: {
168
- Authorization: internalAuthToken,
169
- 'Content-Type': 'application/json',
170
- ...attributionHeaders,
171
- },
172
- body: JSON.stringify(bodyPayload),
173
- }, {
174
- timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
175
- retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
176
- });
177
- return response;
178
- }
179
- catch (err) {
180
- if (err instanceof mondayFetchApi.HttpFetcherError) {
181
- authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
182
- }
183
- throw err;
184
- }
185
- }
186
- static mapGraphResponse(scopedActions, userId, graphResponse) {
187
- const resources = graphResponse ?? {};
188
- return scopedActions.map(scopedAction => {
189
- const { action, scope } = scopedAction;
190
- const { resourceType, resourceId } = this.scopeToResource(scope);
191
- const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
192
- const permit = {
193
- can: permissionResult?.can ?? false,
194
- reason: { key: permissionResult?.reason ?? 'unknown' },
195
- technicalReason: 0,
196
- };
197
- return { scopedAction, permit };
198
- });
199
- }
200
- static async fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload) {
201
- const attributionHeaders = attributionsService.getAttributionsFromApi();
202
- const httpClient = tridentBackendApi.Api.getPart('httpClient');
203
- try {
204
- const response = await httpClient.fetch({
205
- url: {
206
- appName: 'platform',
207
- path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
208
- profile,
209
- },
210
- method: 'POST',
211
- headers: {
212
- Authorization: internalAuthToken,
213
- 'Content-Type': 'application/json',
214
- ...attributionHeaders,
215
- },
216
- body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
217
- }, {
218
- timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
219
- retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
220
- });
221
- return response;
117
+ else {
118
+ const profile = this.getProfile(accountId, userId);
119
+ scopedActionResponseObjects = await clients_platformApi_client.PlatformApiClient.checkPermissions(profile, internalAuthToken, userId, scopedActions);
120
+ apiType = 'platform';
222
121
  }
223
- catch (err) {
224
- if (err instanceof mondayFetchApi.HttpFetcherError) {
225
- authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
122
+ const endTime = perf_hooks.performance.now();
123
+ const time = endTime - startTime;
124
+ // Record metrics for each authorization check
125
+ for (const obj of scopedActionResponseObjects) {
126
+ const { action, scope } = obj.scopedAction;
127
+ const { resourceType } = utils_authorization_utils.scopeToResource(scope);
128
+ const isAuthorized = obj.permit.can;
129
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, 200, time, apiType);
130
+ if (obj.permit.can) {
131
+ prometheusService.incrementAuthorizationSuccess(resourceType, action, apiType);
226
132
  }
227
- throw err;
228
133
  }
229
- }
230
- static toCamelCase(obj) {
231
- return mapKeys__default.default(obj, (_, key) => camelCase__default.default(key));
232
- }
233
- static mapPlatformResponse(response) {
234
- if (!response) {
235
- authorizationInternalService.logger.error({ tag: 'authorization-service', response }, 'AuthorizationService: missing response');
236
- throw new Error('AuthorizationService: missing response');
237
- }
238
- return response.result.map(responseObject => {
239
- const { scopedAction, permit } = responseObject;
240
- const { scope } = scopedAction;
241
- return {
242
- ...responseObject,
243
- scopedAction: { ...scopedAction, scope: this.toCamelCase(scope) },
244
- permit: this.toCamelCase(permit),
245
- };
246
- });
134
+ return scopedActionResponseObjects;
247
135
  }
248
136
  static async isAuthorizedSingular(accountId, userId, resources, action) {
249
137
  const { authorizationObjects } = createAuthorizationParams(resources, action);
@@ -279,7 +167,7 @@ class AuthorizationService {
279
167
  });
280
168
  }
281
169
  catch (err) {
282
- if (err instanceof httpClient.HttpFetcherError) {
170
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
283
171
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'isAuthorizedMultiple');
284
172
  }
285
173
  else {
@@ -298,7 +186,7 @@ class AuthorizationService {
298
186
  if (!isAuthorized) {
299
187
  unauthorizedObjects.push(authorizationObject);
300
188
  }
301
- prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
189
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
302
190
  });
303
191
  if (unauthorizedObjects.length > 0) {
304
192
  authorizationInternalService.logger.info({
@@ -0,0 +1,24 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { GraphIsAllowedDto, GraphIsAllowedResponse } from '../types/graph-api.types';
3
+ /**
4
+ * Client for handling Graph API authorization operations
5
+ */
6
+ export declare class GraphApiClient {
7
+ /**
8
+ * Builds the request body for Graph API calls
9
+ */
10
+ static buildRequestBody(scopedActions: ScopedAction[]): GraphIsAllowedDto;
11
+ /**
12
+ * Fetches authorization data from the Graph API
13
+ */
14
+ static fetchPermissions(internalAuthToken: string, scopedActions: ScopedAction[]): Promise<GraphIsAllowedResponse>;
15
+ /**
16
+ * Maps Graph API response to the expected format
17
+ */
18
+ static mapResponse(scopedActions: ScopedAction[], graphResponse: GraphIsAllowedResponse): ScopedActionResponseObject[];
19
+ /**
20
+ * Performs a complete authorization check using the Graph API
21
+ */
22
+ static checkPermissions(internalAuthToken: string, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
23
+ }
24
+ //# sourceMappingURL=graph-api.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-api.client.d.ts","sourceRoot":"","sources":["../../src/clients/graph-api.client.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EACZ,0BAA0B,EAG3B,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EAIvB,MAAM,0BAA0B,CAAC;AAMlC;;GAEG;AACH,qBAAa,cAAc;IACzB;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,iBAAiB;IAyBzE;;OAEG;WACU,gBAAgB,CAC3B,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,sBAAsB,CAAC;IA2ClC;;OAEG;IACH,MAAM,CAAC,WAAW,CAChB,aAAa,EAAE,YAAY,EAAE,EAC7B,aAAa,EAAE,sBAAsB,GACpC,0BAA0B,EAAE;IAsC/B;;OAEG;WACU,gBAAgB,CAC3B,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAIzC"}
@@ -0,0 +1,123 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
4
+ const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
5
+ const types_scopedActionsContracts = require('../types/scoped-actions-contracts.js');
6
+ const authorizationInternalService = require('../authorization-internal-service.js');
7
+ const attributionsService = require('../attributions-service.js');
8
+ const utils_authorization_utils = require('../utils/authorization.utils.js');
9
+ const prometheusService = require('../prometheus-service.js');
10
+
11
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
12
+ /**
13
+ * Client for handling Graph API authorization operations
14
+ */
15
+ class GraphApiClient {
16
+ /**
17
+ * Builds the request body for Graph API calls
18
+ */
19
+ static buildRequestBody(scopedActions) {
20
+ const resourcesAccumulator = {};
21
+ for (const { action, scope } of scopedActions) {
22
+ const { resourceType, resourceId } = utils_authorization_utils.scopeToResource(scope);
23
+ if (!resourcesAccumulator[resourceType]) {
24
+ resourcesAccumulator[resourceType] = {};
25
+ }
26
+ if (!resourcesAccumulator[resourceType][resourceId]) {
27
+ resourcesAccumulator[resourceType][resourceId] = new Set();
28
+ }
29
+ resourcesAccumulator[resourceType][resourceId].add(action);
30
+ }
31
+ const resourcesPayload = {};
32
+ for (const [resourceType, idMap] of Object.entries(resourcesAccumulator)) {
33
+ resourcesPayload[resourceType] = {};
34
+ for (const [idStr, actionsSet] of Object.entries(idMap)) {
35
+ const idNum = Number(idStr);
36
+ resourcesPayload[resourceType][idNum] = Array.from(actionsSet);
37
+ }
38
+ }
39
+ return resourcesPayload;
40
+ }
41
+ /**
42
+ * Fetches authorization data from the Graph API
43
+ */
44
+ static async fetchPermissions(internalAuthToken, scopedActions) {
45
+ const httpClient = tridentBackendApi.Api.getPart('httpClient');
46
+ const attributionHeaders = attributionsService.getAttributionsFromApi();
47
+ const bodyPayload = this.buildRequestBody(scopedActions);
48
+ try {
49
+ const response = await httpClient.fetch({
50
+ url: {
51
+ appName: 'authorization-graph',
52
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
53
+ },
54
+ method: 'POST',
55
+ headers: {
56
+ Authorization: internalAuthToken,
57
+ 'Content-Type': 'application/json',
58
+ ...attributionHeaders,
59
+ },
60
+ body: JSON.stringify(bodyPayload),
61
+ }, {
62
+ timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
63
+ retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
64
+ });
65
+ return response;
66
+ }
67
+ catch (err) {
68
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
69
+ authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
70
+ if (scopedActions.length > 0) {
71
+ prometheusService.incrementAuthorizationError(utils_authorization_utils.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status, 'graph');
72
+ }
73
+ }
74
+ throw err;
75
+ }
76
+ }
77
+ /**
78
+ * Maps Graph API response to the expected format
79
+ */
80
+ static mapResponse(scopedActions, graphResponse) {
81
+ const resources = graphResponse ?? {};
82
+ return scopedActions.map(scopedAction => {
83
+ const { action, scope } = scopedAction;
84
+ const { resourceType, resourceId } = utils_authorization_utils.scopeToResource(scope);
85
+ const permissionResult = resources?.[resourceType]?.[String(resourceId)]?.[action];
86
+ const graphReason = permissionResult?.reason;
87
+ let reasonKey;
88
+ let additionalOptions = {};
89
+ let technicalReason = types_scopedActionsContracts.PermitTechnicalReason.NO_REASON;
90
+ if (typeof graphReason === 'string') {
91
+ reasonKey = graphReason;
92
+ }
93
+ else if (graphReason && typeof graphReason === 'object') {
94
+ reasonKey = graphReason.key ?? 'unknown';
95
+ additionalOptions = graphReason.additionalOptions ?? {};
96
+ if (graphReason.technicalReason !== undefined) {
97
+ technicalReason = (graphReason.technicalReason ?? types_scopedActionsContracts.PermitTechnicalReason.NO_REASON);
98
+ }
99
+ }
100
+ else {
101
+ reasonKey = 'unknown';
102
+ }
103
+ const permit = {
104
+ can: permissionResult?.can ?? false,
105
+ reason: {
106
+ key: reasonKey,
107
+ ...additionalOptions,
108
+ },
109
+ technicalReason,
110
+ };
111
+ return { scopedAction, permit };
112
+ });
113
+ }
114
+ /**
115
+ * Performs a complete authorization check using the Graph API
116
+ */
117
+ static async checkPermissions(internalAuthToken, scopedActions) {
118
+ const response = await this.fetchPermissions(internalAuthToken, scopedActions);
119
+ return this.mapResponse(scopedActions, response);
120
+ }
121
+ }
122
+
123
+ exports.GraphApiClient = GraphApiClient;
@@ -0,0 +1,31 @@
1
+ import { ScopedAction, ScopedActionResponseObject } from '../types/scoped-actions-contracts';
2
+ import { PlatformProfile } from '../attributions-service';
3
+ type ScopedActionPlatformPayload = Omit<ScopedAction, 'scope'> & {
4
+ scope: Record<string, number>;
5
+ };
6
+ interface CanActionsInScopesResponse {
7
+ result: ScopedActionResponseObject[];
8
+ }
9
+ /**
10
+ * Client for handling Platform API authorization operations
11
+ */
12
+ export declare class PlatformApiClient {
13
+ /**
14
+ * Builds the request payload for Platform API calls
15
+ */
16
+ static buildRequestPayload(scopedActions: ScopedAction[]): ScopedActionPlatformPayload[];
17
+ /**
18
+ * Fetches authorization data from the Platform API
19
+ */
20
+ static fetchPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActionsPayload: ScopedActionPlatformPayload[]): Promise<CanActionsInScopesResponse>;
21
+ /**
22
+ * Maps Platform API response to the expected format
23
+ */
24
+ static mapResponse(response: CanActionsInScopesResponse): ScopedActionResponseObject[];
25
+ /**
26
+ * Performs a complete authorization check using the Platform API
27
+ */
28
+ static checkPermissions(profile: PlatformProfile, internalAuthToken: string, userId: number, scopedActions: ScopedAction[]): Promise<ScopedActionResponseObject[]>;
29
+ }
30
+ export {};
31
+ //# sourceMappingURL=platform-api.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-api.client.d.ts","sourceRoot":"","sources":["../../src/clients/platform-api.client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;AAE7F,OAAO,EAA0B,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAOlF,KAAK,2BAA2B,GAAG,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,UAAU,0BAA0B;IAClC,MAAM,EAAE,0BAA0B,EAAE,CAAC;CACtC;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,aAAa,EAAE,YAAY,EAAE,GAAG,2BAA2B,EAAE;IAOxF;;OAEG;WACU,gBAAgB,CAC3B,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,oBAAoB,EAAE,2BAA2B,EAAE,GAClD,OAAO,CAAC,0BAA0B,CAAC;IAuCtC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,0BAA0B,GAAG,0BAA0B,EAAE;IAkBtF;;OAEG;WACU,gBAAgB,CAC3B,OAAO,EAAE,eAAe,EACxB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;CAKzC"}
@@ -0,0 +1,89 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const tridentBackendApi = require('@mondaydotcomorg/trident-backend-api');
4
+ const mondayFetchApi = require('@mondaydotcomorg/monday-fetch-api');
5
+ const authorizationInternalService = require('../authorization-internal-service.js');
6
+ const attributionsService = require('../attributions-service.js');
7
+ const utils_authorization_utils = require('../utils/authorization.utils.js');
8
+ const prometheusService = require('../prometheus-service.js');
9
+
10
+ const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
11
+ /**
12
+ * Client for handling Platform API authorization operations
13
+ */
14
+ class PlatformApiClient {
15
+ /**
16
+ * Builds the request payload for Platform API calls
17
+ */
18
+ static buildRequestPayload(scopedActions) {
19
+ return scopedActions.map(scopedAction => ({
20
+ ...scopedAction,
21
+ scope: utils_authorization_utils.toSnakeCase(scopedAction.scope),
22
+ }));
23
+ }
24
+ /**
25
+ * Fetches authorization data from the Platform API
26
+ */
27
+ static async fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload) {
28
+ const attributionHeaders = attributionsService.getAttributionsFromApi();
29
+ const httpClient = tridentBackendApi.Api.getPart('httpClient');
30
+ try {
31
+ const response = await httpClient.fetch({
32
+ url: {
33
+ appName: 'platform',
34
+ path: PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH,
35
+ profile,
36
+ },
37
+ method: 'POST',
38
+ headers: {
39
+ Authorization: internalAuthToken,
40
+ 'Content-Type': 'application/json',
41
+ ...attributionHeaders,
42
+ },
43
+ body: JSON.stringify({ user_id: userId, scoped_actions: scopedActionsPayload }),
44
+ }, {
45
+ timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
46
+ retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
47
+ });
48
+ return response;
49
+ }
50
+ catch (err) {
51
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
52
+ authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
53
+ if (scopedActionsPayload.length > 0) {
54
+ const { resourceType } = utils_authorization_utils.scopeToResource(utils_authorization_utils.toCamelCase(scopedActionsPayload[0].scope));
55
+ prometheusService.incrementAuthorizationError(resourceType, scopedActionsPayload[0].action, err.status, 'platform');
56
+ }
57
+ }
58
+ throw err;
59
+ }
60
+ }
61
+ /**
62
+ * Maps Platform API response to the expected format
63
+ */
64
+ static mapResponse(response) {
65
+ if (!response) {
66
+ authorizationInternalService.logger.error({ tag: 'platform-api-client', response }, 'PlatformApiClient: missing response');
67
+ throw new Error('PlatformApiClient: missing response');
68
+ }
69
+ return response.result.map(responseObject => {
70
+ const { scopedAction, permit } = responseObject;
71
+ const { scope } = scopedAction;
72
+ return {
73
+ ...responseObject,
74
+ scopedAction: { ...scopedAction, scope: utils_authorization_utils.toCamelCase(scope) },
75
+ permit: utils_authorization_utils.toCamelCase(permit),
76
+ };
77
+ });
78
+ }
79
+ /**
80
+ * Performs a complete authorization check using the Platform API
81
+ */
82
+ static async checkPermissions(profile, internalAuthToken, userId, scopedActions) {
83
+ const scopedActionsPayload = this.buildRequestPayload(scopedActions);
84
+ const platformResponse = await this.fetchPermissions(profile, internalAuthToken, userId, scopedActionsPayload);
85
+ return this.mapResponse(platformResponse);
86
+ }
87
+ }
88
+
89
+ exports.PlatformApiClient = PlatformApiClient;
@@ -30,14 +30,6 @@ 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;
41
33
  private static isAuthorizedSingular;
42
34
  private static isAuthorizedMultiple;
43
35
  }
@@ -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;AAc1C,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;AA6BD,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;IAsBxC,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;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,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":"AACA,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;AAMD,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;mBA6DnB,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"}