@forge/bridge 5.10.3-next.1-experimental-919607a → 5.11.0-next.3

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/CHANGELOG.md CHANGED
@@ -1,12 +1,24 @@
1
1
  # @forge/bridge
2
2
 
3
- ## 5.10.3-next.1-experimental-919607a
3
+ ## 5.11.0-next.3
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - Updated dependencies [e21f32f]
8
- - Updated dependencies [545ecc1]
9
- - @forge/manifest@11.4.0-next.1-experimental-919607a
7
+ - Updated dependencies [6b7a4ef]
8
+ - Updated dependencies [dfa2aa6]
9
+ - Updated dependencies [8db2311]
10
+ - @forge/manifest@12.0.0-next.3
11
+
12
+ ## 5.11.0-next.2
13
+
14
+ ### Minor Changes
15
+
16
+ - f058dd8: Expose Permissions API in @forge/bridge for Custom UI apps
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [eadb4a6]
21
+ - @forge/manifest@11.4.0-next.2
10
22
 
11
23
  ## 5.10.3-next.1
12
24
 
@@ -1,2 +1,3 @@
1
1
  export * from './permissions';
2
+ export * from './permissionsUtil';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/permissions/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/permissions/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC"}
@@ -2,3 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  tslib_1.__exportStar(require("./permissions"), exports);
5
+ tslib_1.__exportStar(require("./permissionsUtil"), exports);
@@ -0,0 +1,39 @@
1
+ import type { External } from '@forge/manifest';
2
+ import type { RuntimePermissions } from '../types';
3
+ declare const RESOURCE_TYPES: readonly ["fonts", "styles", "frames", "images", "media", "scripts"];
4
+ export declare type ResourceType = (typeof RESOURCE_TYPES)[number];
5
+ declare const FETCH_TYPES: readonly ["backend", "client"];
6
+ export declare type FetchType = (typeof FETCH_TYPES)[number];
7
+ export interface PermissionRequirements {
8
+ scopes?: string[];
9
+ external?: {
10
+ fetch?: {
11
+ backend?: string[];
12
+ client?: string[];
13
+ };
14
+ fonts?: string[];
15
+ styles?: string[];
16
+ frames?: string[];
17
+ images?: string[];
18
+ media?: string[];
19
+ scripts?: string[];
20
+ };
21
+ content?: Record<string, unknown>;
22
+ }
23
+ export declare type MissingPermissions = PermissionRequirements;
24
+ export interface PermissionCheckResult {
25
+ granted: boolean;
26
+ missing: MissingPermissions | null;
27
+ }
28
+ export interface PermissionUtils {
29
+ hasScope: (scope: string) => boolean;
30
+ canFetchFrom: (type: FetchType, url: string) => boolean;
31
+ canLoadResource: (type: ResourceType, url: string) => boolean;
32
+ getScopes: () => string[];
33
+ getExternalPermissions: () => External | undefined;
34
+ hasAnyPermissions: () => boolean;
35
+ }
36
+ export declare function createPermissionUtils(runtimePermissions: RuntimePermissions | undefined): PermissionUtils | null;
37
+ export declare function checkPermissions(requiredPermissions: PermissionRequirements, runtimePermissions?: RuntimePermissions | undefined): Promise<PermissionCheckResult>;
38
+ export {};
39
+ //# sourceMappingURL=permissionsUtil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionsUtil.d.ts","sourceRoot":"","sources":["../../src/permissions/permissionsUtil.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAoBnD,QAAA,MAAM,cAAc,sEAAuE,CAAC;AAC5F,oBAAY,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAK3D,QAAA,MAAM,WAAW,gCAAiC,CAAC;AACnD,oBAAY,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAKrD,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE;YACN,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;YACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAKD,oBAAY,kBAAkB,GAAG,sBAAsB,CAAC;AAKxD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACpC;AAKD,MAAM,WAAW,eAAe;IAI9B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAOrC,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAOxD,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAK9D,SAAS,EAAE,MAAM,MAAM,EAAE,CAAC;IAK1B,sBAAsB,EAAE,MAAM,QAAQ,GAAG,SAAS,CAAC;IAKnD,iBAAiB,EAAE,MAAM,OAAO,CAAC;CAClC;AAOD,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,SAAS,GAAG,eAAe,GAAG,IAAI,CAmDhH;AAiGD,wBAAsB,gBAAgB,CACpC,mBAAmB,EAAE,sBAAsB,EAC3C,kBAAkB,CAAC,EAAE,kBAAkB,GAAG,SAAS,GAClD,OAAO,CAAC,qBAAqB,CAAC,CA+ChC"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkPermissions = exports.createPermissionUtils = void 0;
4
+ const egress_1 = require("@forge/egress");
5
+ const view_1 = require("../view");
6
+ function extractUrlString(url) {
7
+ if (typeof url === 'string') {
8
+ return url;
9
+ }
10
+ if ('address' in url && url.address) {
11
+ return url.address;
12
+ }
13
+ return url.remote || '';
14
+ }
15
+ const RESOURCE_TYPES = ['fonts', 'styles', 'frames', 'images', 'media', 'scripts'];
16
+ const FETCH_TYPES = ['backend', 'client'];
17
+ function createPermissionUtils(runtimePermissions) {
18
+ if (!runtimePermissions) {
19
+ return null;
20
+ }
21
+ const { scopes, external = {} } = runtimePermissions;
22
+ const scopeArray = Array.isArray(scopes) ? scopes : Object.keys(scopes || {});
23
+ return {
24
+ hasScope: (scope) => scopeArray.includes(scope),
25
+ canFetchFrom: (type, url) => {
26
+ var _a;
27
+ const fetchUrls = (_a = external.fetch) === null || _a === void 0 ? void 0 : _a[type];
28
+ if (!(fetchUrls === null || fetchUrls === void 0 ? void 0 : fetchUrls.length))
29
+ return false;
30
+ const allowList = fetchUrls.map(extractUrlString).filter((u) => u.length > 0);
31
+ if (allowList.length === 0)
32
+ return false;
33
+ const egressFilter = new egress_1.EgressFilteringService(allowList);
34
+ const egressFilterWithCSP = egressFilter;
35
+ return type === 'client' ? egressFilterWithCSP.isValidUrlCSP(url) : egressFilter.isValidUrl(url);
36
+ },
37
+ canLoadResource: (type, url) => {
38
+ const resourceUrls = external[type];
39
+ if (!(resourceUrls === null || resourceUrls === void 0 ? void 0 : resourceUrls.length))
40
+ return false;
41
+ const allowList = resourceUrls.map(extractUrlString).filter((u) => u.length > 0);
42
+ if (allowList.length === 0)
43
+ return false;
44
+ const egressFilter = new egress_1.EgressFilteringService(allowList);
45
+ const egressFilterWithCSP = egressFilter;
46
+ return egressFilterWithCSP.isValidUrlCSP(url);
47
+ },
48
+ getScopes: () => scopeArray,
49
+ getExternalPermissions: () => external,
50
+ hasAnyPermissions: () => scopeArray.length > 0 || Object.keys(external).length > 0
51
+ };
52
+ }
53
+ exports.createPermissionUtils = createPermissionUtils;
54
+ function checkScopes(requiredScopes, permissionUtils) {
55
+ if (!(requiredScopes === null || requiredScopes === void 0 ? void 0 : requiredScopes.length)) {
56
+ return undefined;
57
+ }
58
+ const missingScopes = requiredScopes.filter((scope) => !permissionUtils.hasScope(scope));
59
+ return missingScopes.length > 0 ? missingScopes : undefined;
60
+ }
61
+ function checkFetchPermissions(requiredFetch, permissionUtils) {
62
+ if (!(requiredFetch === null || requiredFetch === void 0 ? void 0 : requiredFetch.fetch)) {
63
+ return undefined;
64
+ }
65
+ const missingFetch = {};
66
+ FETCH_TYPES.forEach((type) => {
67
+ var _a;
68
+ const requiredUrls = (_a = requiredFetch.fetch) === null || _a === void 0 ? void 0 : _a[type];
69
+ if (requiredUrls === null || requiredUrls === void 0 ? void 0 : requiredUrls.length) {
70
+ const missingUrls = requiredUrls.filter((url) => !permissionUtils.canFetchFrom(type, url));
71
+ if (missingUrls.length > 0) {
72
+ missingFetch[type] = missingUrls;
73
+ }
74
+ }
75
+ });
76
+ return Object.keys(missingFetch).length > 0 ? missingFetch : undefined;
77
+ }
78
+ function checkResourcePermissions(requiredExternal, permissionUtils) {
79
+ const missingResources = {};
80
+ RESOURCE_TYPES.forEach((type) => {
81
+ const requiredUrls = requiredExternal === null || requiredExternal === void 0 ? void 0 : requiredExternal[type];
82
+ if (requiredUrls === null || requiredUrls === void 0 ? void 0 : requiredUrls.length) {
83
+ const missingUrls = requiredUrls.filter((url) => !permissionUtils.canLoadResource(type, url));
84
+ if (missingUrls.length > 0) {
85
+ missingResources[type] = missingUrls;
86
+ }
87
+ }
88
+ });
89
+ return Object.keys(missingResources).length > 0 ? missingResources : undefined;
90
+ }
91
+ function checkExternalPermissions(requiredExternal, permissionUtils) {
92
+ if (!requiredExternal) {
93
+ return undefined;
94
+ }
95
+ const missingFetch = checkFetchPermissions(requiredExternal, permissionUtils);
96
+ const missingResources = checkResourcePermissions(requiredExternal, permissionUtils);
97
+ if (!missingFetch && !missingResources) {
98
+ return undefined;
99
+ }
100
+ const missingExternal = {};
101
+ if (missingFetch) {
102
+ missingExternal.fetch = missingFetch;
103
+ }
104
+ if (missingResources) {
105
+ Object.assign(missingExternal, missingResources);
106
+ }
107
+ return missingExternal;
108
+ }
109
+ async function checkPermissions(requiredPermissions, runtimePermissions) {
110
+ var _a;
111
+ if (!requiredPermissions) {
112
+ return { granted: false, missing: null };
113
+ }
114
+ if (!((_a = requiredPermissions.scopes) === null || _a === void 0 ? void 0 : _a.length) && !requiredPermissions.external) {
115
+ return { granted: true, missing: null };
116
+ }
117
+ let permissionsToCheck = runtimePermissions;
118
+ if (!permissionsToCheck) {
119
+ const context = await view_1.view.getContext();
120
+ permissionsToCheck = context.permissions;
121
+ }
122
+ const permissionUtils = createPermissionUtils(permissionsToCheck);
123
+ if (!permissionUtils) {
124
+ return { granted: false, missing: null };
125
+ }
126
+ const missing = {};
127
+ let hasAllRequiredPermissions = true;
128
+ const missingScopes = checkScopes(requiredPermissions.scopes, permissionUtils);
129
+ if (missingScopes) {
130
+ missing.scopes = missingScopes;
131
+ hasAllRequiredPermissions = false;
132
+ }
133
+ const missingExternal = checkExternalPermissions(requiredPermissions.external, permissionUtils);
134
+ if (missingExternal) {
135
+ missing.external = missingExternal;
136
+ hasAllRequiredPermissions = false;
137
+ }
138
+ return {
139
+ granted: hasAllRequiredPermissions,
140
+ missing: hasAllRequiredPermissions ? null : missing
141
+ };
142
+ }
143
+ exports.checkPermissions = checkPermissions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/bridge",
3
- "version": "5.10.3-next.1-experimental-919607a",
3
+ "version": "5.11.0-next.3",
4
4
  "description": "Forge bridge API for custom UI apps",
5
5
  "author": "Atlassian",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -20,7 +20,7 @@
20
20
  "@forge/resolver": "1.7.1",
21
21
  "@statsig/js-client": "3.18.2",
22
22
  "@types/history": "^4.7.11",
23
- "@forge/manifest": "11.4.0-next.1-experimental-919607a",
23
+ "@forge/manifest": "12.0.0-next.3",
24
24
  "@types/iframe-resizer": "^3.5.8",
25
25
  "iframe-resizer": "^4.4.5",
26
26
  "uuid": "^9.0.1"