@lvce-editor/shared-process 0.31.6 → 0.32.1
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/package.json +2 -2
- package/src/parts/ContentSecurityPolicyDocument/ContentSecurityPolicyDocument.js +11 -1
- package/src/parts/CreateWebViewServer/CreateWebViewServer.js +24 -0
- package/src/parts/CreateWebViewServerHandler/CreateWebViewServerHandler.js +62 -0
- package/src/parts/ExtensionManagement/ExtensionManagement.ipc.js +1 -0
- package/src/parts/ExtensionManagement/ExtensionManagementLanguages.js +19 -0
- package/src/parts/GetTestRequestResponse/GetTestRequestResponse.js +2 -0
- package/src/parts/IsGitpod/IsGitpod.js +2 -0
- package/src/parts/Module/Module.js +2 -0
- package/src/parts/ModuleId/ModuleId.js +1 -0
- package/src/parts/ModuleMap/ModuleMap.js +4 -0
- package/src/parts/Platform/Platform.js +3 -3
- package/src/parts/PlatformPaths/PlatformPaths.js +3 -0
- package/src/parts/WebViewServer/WebViewServer.ipc.js +6 -0
- package/src/parts/WebViewServer/WebViewServer.js +21 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.1",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@lvce-editor/assert": "^1.2.0",
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.32.1",
|
|
22
22
|
"@lvce-editor/ipc": "^9.4.0",
|
|
23
23
|
"@lvce-editor/json-rpc": "^1.4.0",
|
|
24
24
|
"@lvce-editor/jsonc-parser": "^1.4.0",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import * as GetContentSecurityPolicy from '../GetContentSecurityPolicy/GetContentSecurityPolicy.js';
|
|
2
2
|
import * as IsElectron from '../IsElectron/IsElectron.js';
|
|
3
|
+
import * as IsGitpod from '../IsGitpod/IsGitpod.js';
|
|
4
|
+
const getGitpodPreviewUrl = (port) => {
|
|
5
|
+
const workspaceId = process.env.GITPOD_WORKSPACE_ID;
|
|
6
|
+
const cluster = process.env.GITPOD_WORKSPACE_CLUSTER_HOST;
|
|
7
|
+
const url = `https://${port}-${workspaceId}.${cluster}`;
|
|
8
|
+
return url;
|
|
9
|
+
};
|
|
3
10
|
export const value = GetContentSecurityPolicy.getContentSecurityPolicy([
|
|
4
11
|
`default-src 'none'`,
|
|
5
12
|
`font-src 'self'`,
|
|
@@ -7,6 +14,9 @@ export const value = GetContentSecurityPolicy.getContentSecurityPolicy([
|
|
|
7
14
|
`media-src 'self'`,
|
|
8
15
|
`script-src 'self'`,
|
|
9
16
|
`style-src 'self'`,
|
|
10
|
-
`frame-
|
|
17
|
+
`frame-ancestors 'none' `,
|
|
18
|
+
IsGitpod.isGitpod
|
|
19
|
+
? `frame-src 'self' ${getGitpodPreviewUrl(3001)} ${getGitpodPreviewUrl(3002)}`
|
|
20
|
+
: `frame-src 'self' http://localhost:3001 http://localhost:3002`,
|
|
11
21
|
...(IsElectron.isElectron ? [] : [`manifest-src 'self'`]),
|
|
12
22
|
]);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { VError } from '@lvce-editor/verror';
|
|
2
|
+
import { createServer } from 'node:http';
|
|
3
|
+
import * as Promises from '../Promises/Promises.js';
|
|
4
|
+
export const createWebViewServer = async (port) => {
|
|
5
|
+
try {
|
|
6
|
+
const server = createServer();
|
|
7
|
+
const { resolve, promise } = Promises.withResolvers();
|
|
8
|
+
server.listen(port, resolve);
|
|
9
|
+
await promise;
|
|
10
|
+
return {
|
|
11
|
+
handler: undefined,
|
|
12
|
+
setHandler(handleRequest) {
|
|
13
|
+
if (this.handler) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
this.handler = this.handler;
|
|
17
|
+
server.on('request', handleRequest);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new VError(error, `Failed to start webview server`);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import * as GetContentSecurityPolicy from '../GetContentSecurityPolicy/GetContentSecurityPolicy.js';
|
|
6
|
+
import * as SetHeaders from '../SetHeaders/SetHeaders.js';
|
|
7
|
+
const getPathName = (request) => {
|
|
8
|
+
const { pathname } = new URL(request.url || '', `https://${request.headers.host}`);
|
|
9
|
+
return pathname;
|
|
10
|
+
};
|
|
11
|
+
const textMimeType = {
|
|
12
|
+
'.html': 'text/html',
|
|
13
|
+
'.js': 'text/javascript',
|
|
14
|
+
'.ts': 'text/javascript',
|
|
15
|
+
'.mjs': 'text/javascript',
|
|
16
|
+
'.json': 'application/json',
|
|
17
|
+
'.css': 'text/css',
|
|
18
|
+
'.svg': 'image/svg+xml',
|
|
19
|
+
'.avif': 'image/avif',
|
|
20
|
+
'.woff': 'application/font-woff',
|
|
21
|
+
'.ttf': 'font/ttf',
|
|
22
|
+
'.png': 'image/png',
|
|
23
|
+
'.jpe': 'image/jpg',
|
|
24
|
+
'.ico': 'image/x-icon',
|
|
25
|
+
'.jpeg': 'image/jpg',
|
|
26
|
+
'.jpg': 'image/jpg',
|
|
27
|
+
'.webp': 'image/webp',
|
|
28
|
+
};
|
|
29
|
+
const getContentType = (filePath) => {
|
|
30
|
+
return textMimeType[extname(filePath)] || 'text/plain';
|
|
31
|
+
};
|
|
32
|
+
export const createHandler = (frameAncestors, webViewRoot) => {
|
|
33
|
+
const csp = GetContentSecurityPolicy.getContentSecurityPolicy([`default-src 'none'`, `script-src 'self'`, `frame-ancestors ${frameAncestors}`]);
|
|
34
|
+
const handleRequest = async (request, response) => {
|
|
35
|
+
let pathName = getPathName(request);
|
|
36
|
+
if (pathName === '/') {
|
|
37
|
+
pathName += 'index.html';
|
|
38
|
+
}
|
|
39
|
+
const filePath = fileURLToPath(`file://${webViewRoot}${pathName}`);
|
|
40
|
+
const isHtml = filePath.endsWith('index.html');
|
|
41
|
+
const contentType = getContentType(filePath);
|
|
42
|
+
if (isHtml) {
|
|
43
|
+
SetHeaders.setHeaders(response, {
|
|
44
|
+
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
45
|
+
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
46
|
+
'Content-Security-Policy': csp,
|
|
47
|
+
'Content-Type': contentType,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// TODO figure out which of these headers are actually needed
|
|
52
|
+
SetHeaders.setHeaders(response, {
|
|
53
|
+
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
54
|
+
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
55
|
+
'Access-Control-Allow-Origin': '*',
|
|
56
|
+
'Content-Type': contentType,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
await pipeline(createReadStream(filePath), response);
|
|
60
|
+
};
|
|
61
|
+
return handleRequest;
|
|
62
|
+
};
|
|
@@ -9,6 +9,7 @@ export const Commands = {
|
|
|
9
9
|
'ExtensionHost.getIconThemeJson': ExtensionHostIconTheme.getIconTheme,
|
|
10
10
|
'ExtensionHost.getLanguageConfiguration': ExtensionHostLanguages.getLanguageConfiguration,
|
|
11
11
|
'ExtensionHost.getLanguages': ExtensionHostLanguages.getLanguages,
|
|
12
|
+
'ExtensionHost.getWebViews': ExtensionHostLanguages.getWebViews,
|
|
12
13
|
'ExtensionHost.watchColorTheme': ExtensionHostColorTheme.watch,
|
|
13
14
|
'ExtensionManagement.disable': ExtensionManagement.disable,
|
|
14
15
|
'ExtensionManagement.enable': ExtensionManagement.enable,
|
|
@@ -38,6 +38,25 @@ export const getLanguages = async () => {
|
|
|
38
38
|
const languages = getLanguagesFromExtensions(extensions);
|
|
39
39
|
return languages;
|
|
40
40
|
};
|
|
41
|
+
const getWebViewsFromExtensions = (extensions) => {
|
|
42
|
+
const webViews = [];
|
|
43
|
+
for (const extension of extensions) {
|
|
44
|
+
if (extension && extension.webViews) {
|
|
45
|
+
for (const webView of extension.webViews) {
|
|
46
|
+
webViews.push({
|
|
47
|
+
id: webView.id,
|
|
48
|
+
path: join(extension.path, webView.path),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return webViews;
|
|
54
|
+
};
|
|
55
|
+
export const getWebViews = async () => {
|
|
56
|
+
const extensions = await ExtensionManagement.getExtensions();
|
|
57
|
+
const webViews = getWebViewsFromExtensions(extensions);
|
|
58
|
+
return webViews;
|
|
59
|
+
};
|
|
41
60
|
const getLanguageConfigurationPathFromExtensions = (extensions, languageId) => {
|
|
42
61
|
for (const extension of extensions) {
|
|
43
62
|
if (extension.languages && extension.languages) {
|
|
@@ -5,6 +5,7 @@ import * as CreateTestOverview from '../CreateTestOverview/CreateTestOverview.js
|
|
|
5
5
|
import * as CrossOriginEmbedderPolicy from '../CrossOriginEmbedderPolicy/CrossOriginEmbedderPolicy.js';
|
|
6
6
|
import * as CrossOriginOpenerPolicy from '../CrossOriginOpenerPolicy/CrossOriginOpenerPolicy.js';
|
|
7
7
|
import * as CrossOriginResourcePolicy from '../CrossOriginResourcePolicy/CrossOriginResourcePolicy.js';
|
|
8
|
+
import * as ContentSecurityPolicyDocument from '../ContentSecurityPolicyDocument/ContentSecurityPolicyDocument.js';
|
|
8
9
|
import * as GetPathName from '../GetPathName/GetPathName.js';
|
|
9
10
|
import * as GetTestPath from '../GetTestPath/GetTestPath.js';
|
|
10
11
|
import * as HttpHeader from '../HttpHeader/HttpHeader.js';
|
|
@@ -21,6 +22,7 @@ export const getTestRequestResponse = async (request, indexHtmlPath) => {
|
|
|
21
22
|
headers: {
|
|
22
23
|
[HttpHeader.CrossOriginEmbedderPolicy]: CrossOriginEmbedderPolicy.value,
|
|
23
24
|
[HttpHeader.CrossOriginResourcePolicy]: CrossOriginResourcePolicy.value,
|
|
25
|
+
[HttpHeader.ContentSecurityPolicy]: ContentSecurityPolicyDocument.value,
|
|
24
26
|
},
|
|
25
27
|
},
|
|
26
28
|
};
|
|
@@ -129,6 +129,8 @@ export const load = (moduleId) => {
|
|
|
129
129
|
return import('../HandleMessagePortForSearchProcess/HandleMessagePortForSearchProcess.ipc.js');
|
|
130
130
|
case ModuleId.FileWatcher:
|
|
131
131
|
return import('../FileWatcher/FileWatcher.ipc.js');
|
|
132
|
+
case ModuleId.WebViewServer:
|
|
133
|
+
return import('../WebViewServer/WebViewServer.ipc.js');
|
|
132
134
|
default:
|
|
133
135
|
throw new Error(`module ${moduleId} not found`);
|
|
134
136
|
}
|
|
@@ -121,6 +121,7 @@ export const getModuleId = (commandId) => {
|
|
|
121
121
|
case 'ExtensionHost.getIconThemeJson':
|
|
122
122
|
case 'ExtensionHost.getLanguageConfiguration':
|
|
123
123
|
case 'ExtensionHost.getLanguages':
|
|
124
|
+
case 'ExtensionHost.getWebViews':
|
|
124
125
|
case 'ExtensionHost.watchColorTheme':
|
|
125
126
|
case 'ExtensionManagement.disable':
|
|
126
127
|
case 'ExtensionManagement.enable':
|
|
@@ -276,6 +277,9 @@ export const getModuleId = (commandId) => {
|
|
|
276
277
|
return ModuleId.HandleMessagePortForSearchProcess;
|
|
277
278
|
case 'FileWatcher.watch':
|
|
278
279
|
return ModuleId.FileWatcher;
|
|
280
|
+
case 'WebViewServer.start':
|
|
281
|
+
case 'WebViewServer.setHandler':
|
|
282
|
+
return ModuleId.WebViewServer;
|
|
279
283
|
default:
|
|
280
284
|
throw new CommandNotFoundError(commandId);
|
|
281
285
|
}
|
|
@@ -41,9 +41,9 @@ export const getAppImageName = () => {
|
|
|
41
41
|
export const getSetupName = () => {
|
|
42
42
|
return 'Lvce-Setup';
|
|
43
43
|
};
|
|
44
|
-
export const version = '0.
|
|
45
|
-
export const commit = '
|
|
46
|
-
export const date = '2024-08-
|
|
44
|
+
export const version = '0.32.1';
|
|
45
|
+
export const commit = 'f51fb63';
|
|
46
|
+
export const date = '2024-08-18T19:59:49.000Z';
|
|
47
47
|
export const getVersion = () => {
|
|
48
48
|
return version;
|
|
49
49
|
};
|
|
@@ -55,6 +55,9 @@ export const getExtensionHostHelperProcessPath = async () => {
|
|
|
55
55
|
const { extensionHostHelperProcessPath } = await import('@lvce-editor/extension-host-helper-process');
|
|
56
56
|
return extensionHostHelperProcessPath;
|
|
57
57
|
};
|
|
58
|
+
export const getWebViewRoot = (relativePath) => {
|
|
59
|
+
return Path.join(Root.root, relativePath);
|
|
60
|
+
};
|
|
58
61
|
export const getRecentlyOpenedPath = () => {
|
|
59
62
|
return Path.join(cacheDir, 'recently-opened.json');
|
|
60
63
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as CreateWebViewServer from '../CreateWebViewServer/CreateWebViewServer.js';
|
|
2
|
+
import * as CreateWebViewServerHandler from '../CreateWebViewServerHandler/CreateWebViewServerHandler.js';
|
|
3
|
+
const state = {
|
|
4
|
+
/**
|
|
5
|
+
* @type {any }
|
|
6
|
+
*/
|
|
7
|
+
promise: undefined,
|
|
8
|
+
};
|
|
9
|
+
// TODO move webview preview
|
|
10
|
+
// server into separate process
|
|
11
|
+
export const start = async (port) => {
|
|
12
|
+
if (!state.promise) {
|
|
13
|
+
state.promise = CreateWebViewServer.createWebViewServer(port);
|
|
14
|
+
}
|
|
15
|
+
return state.promise;
|
|
16
|
+
};
|
|
17
|
+
export const setHandler = async (frameAncestors, webViewRoot) => {
|
|
18
|
+
const server = await state.promise;
|
|
19
|
+
const handler = CreateWebViewServerHandler.createHandler(frameAncestors, webViewRoot);
|
|
20
|
+
server.setHandler(handler);
|
|
21
|
+
};
|