@forge/bridge 5.10.1-next.6 → 5.10.2-experimental-60ea29e
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 +46 -0
- package/LICENSE.txt +1 -1
- package/out/permissions/index.d.ts +1 -0
- package/out/permissions/index.d.ts.map +1 -1
- package/out/permissions/index.js +1 -0
- package/out/permissions/permissionsUtil.d.ts +39 -0
- package/out/permissions/permissionsUtil.d.ts.map +1 -0
- package/out/permissions/permissionsUtil.js +143 -0
- package/out/view/emitReadyEvent.d.ts.map +1 -1
- package/out/view/emitReadyEvent.js +12 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @forge/bridge
|
|
2
2
|
|
|
3
|
+
## 5.10.2-experimental-60ea29e
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f058dd8: Expose Permissions API in @forge/bridge for Custom UI apps
|
|
8
|
+
|
|
9
|
+
## 5.10.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 4205052: Send emitReadyEvent calls over the bridge for usage in static macros
|
|
14
|
+
- Updated dependencies [73c9329]
|
|
15
|
+
- Updated dependencies [1eae7ab]
|
|
16
|
+
- Updated dependencies [b96a445]
|
|
17
|
+
- @forge/manifest@11.3.2
|
|
18
|
+
|
|
19
|
+
## 5.10.2-next.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [1eae7ab]
|
|
24
|
+
- @forge/manifest@11.3.2-next.1
|
|
25
|
+
|
|
26
|
+
## 5.10.2-next.0
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 4205052: Send emitReadyEvent calls over the bridge for usage in static macros
|
|
31
|
+
- Updated dependencies [73c9329]
|
|
32
|
+
- Updated dependencies [b96a445]
|
|
33
|
+
- @forge/manifest@11.3.2-next.0
|
|
34
|
+
|
|
35
|
+
## 5.10.1
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [10f70c2]
|
|
40
|
+
- Updated dependencies [cd0a085]
|
|
41
|
+
- Updated dependencies [16e7d61]
|
|
42
|
+
- Updated dependencies [f7c9fcc]
|
|
43
|
+
- Updated dependencies [b799627]
|
|
44
|
+
- Updated dependencies [29aa91c]
|
|
45
|
+
- Updated dependencies [8b66e6f]
|
|
46
|
+
- @forge/manifest@11.3.1
|
|
47
|
+
- @forge/egress@2.3.1
|
|
48
|
+
|
|
3
49
|
## 5.10.1-next.6
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/LICENSE.txt
CHANGED
|
@@ -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"}
|
package/out/permissions/index.js
CHANGED
|
@@ -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;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emitReadyEvent.d.ts","sourceRoot":"","sources":["../../src/view/emitReadyEvent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"emitReadyEvent.d.ts","sourceRoot":"","sources":["../../src/view/emitReadyEvent.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,QAAa,QAAQ,IAAI,CAiBnD,CAAC"}
|
|
@@ -3,11 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.emitReadyEvent = void 0;
|
|
4
4
|
const events_1 = require("../events/events");
|
|
5
5
|
const view_1 = require("./view");
|
|
6
|
+
const bridge_1 = require("../bridge");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const callBridge = (0, bridge_1.getCallBridge)();
|
|
6
9
|
const EXTENSION_READY = 'EXTENSION_READY';
|
|
7
10
|
const emitReadyEvent = async () => {
|
|
8
11
|
const context = await view_1.view.getContext();
|
|
9
12
|
await events_1.events.emit(EXTENSION_READY, {
|
|
10
13
|
localId: context.localId
|
|
11
14
|
});
|
|
15
|
+
try {
|
|
16
|
+
const success = await callBridge('emitReadyEvent');
|
|
17
|
+
if (success === false) {
|
|
18
|
+
throw new errors_1.BridgeAPIError('Unable to emit ready event.');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new errors_1.BridgeAPIError('Unable to emit ready event.');
|
|
23
|
+
}
|
|
12
24
|
};
|
|
13
25
|
exports.emitReadyEvent = emitReadyEvent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge/bridge",
|
|
3
|
-
"version": "5.10.
|
|
3
|
+
"version": "5.10.2-experimental-60ea29e",
|
|
4
4
|
"description": "Forge bridge API for custom UI apps",
|
|
5
5
|
"author": "Atlassian",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@atlaskit/adf-schema": "^48.0.0",
|
|
17
17
|
"@atlaskit/tokens": "^1.58.0",
|
|
18
|
-
"@forge/egress": "^2.3.1
|
|
18
|
+
"@forge/egress": "^2.3.1",
|
|
19
19
|
"@forge/i18n": "0.0.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.3.
|
|
23
|
+
"@forge/manifest": "11.3.2",
|
|
24
24
|
"@types/iframe-resizer": "^3.5.8",
|
|
25
25
|
"iframe-resizer": "^4.4.5",
|
|
26
26
|
"uuid": "^9.0.1"
|