@lvce-editor/shared-process 0.33.4 → 0.33.6
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 +5 -5
- package/src/parts/ContentSecurityPolicyDocument/ContentSecurityPolicyDocument.js +24 -11
- package/src/parts/ExportStatic/ExportStatic.js +12 -0
- package/src/parts/GetElectronFileResponse/GetElectronFileResponse.js +14 -6
- package/src/parts/GetElectronFileResponseAbsolutePath/GetElectronFileResponseAbsolutePath.js +5 -0
- package/src/parts/GetElectronFileResponseRelativePath/GetElectronFileResponseRelativePath.js +21 -3
- package/src/parts/GetGitpodPreviewUrl/GetGitpodPreviewUrl.js +6 -0
- package/src/parts/LaunchPreviewProcess/LaunchPreviewProcess.js +13 -2
- package/src/parts/ModuleMap/ModuleMap.js +2 -0
- package/src/parts/Platform/Platform.js +3 -3
- package/src/parts/PreviewProcess/PreviewProcess.js +4 -0
- package/src/parts/Scheme/Scheme.js +1 -0
- package/src/parts/WebViewServer/WebViewServer.ipc.js +2 -0
- package/src/parts/WebViewServer/WebViewServer.js +23 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.33.
|
|
3
|
+
"version": "0.33.6",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@lvce-editor/assert": "^1.
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.33.
|
|
22
|
-
"@lvce-editor/ipc": "^10.
|
|
20
|
+
"@lvce-editor/assert": "^1.3.0",
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.33.6",
|
|
22
|
+
"@lvce-editor/ipc": "^10.2.1",
|
|
23
23
|
"@lvce-editor/json-rpc": "^3.0.0",
|
|
24
24
|
"@lvce-editor/jsonc-parser": "^1.4.0",
|
|
25
25
|
"@lvce-editor/pretty-error": "^1.6.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@lvce-editor/typescript-compile-process": "^1.2.0",
|
|
36
36
|
"@lvce-editor/pty-host": "^2.0.0",
|
|
37
37
|
"@lvce-editor/embeds-process": "^1.5.0",
|
|
38
|
-
"@lvce-editor/preview-process": "^
|
|
38
|
+
"@lvce-editor/preview-process": "^2.10.0",
|
|
39
39
|
"open": "^10.1.0",
|
|
40
40
|
"tail": "^2.2.6",
|
|
41
41
|
"tmp-promise": "^3.0.3",
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import * as GetContentSecurityPolicy from '../GetContentSecurityPolicy/GetContentSecurityPolicy.js';
|
|
2
|
+
import * as GetGitpodPreviewUrl from '../GetGitpodPreviewUrl/GetGitpodPreviewUrl.js';
|
|
2
3
|
import * as IsElectron from '../IsElectron/IsElectron.js';
|
|
3
4
|
import * as IsGitpod from '../IsGitpod/IsGitpod.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import * as Scheme from '../Scheme/Scheme.js';
|
|
6
|
+
const getFrameSrc = () => {
|
|
7
|
+
// TODO make ports configurable
|
|
8
|
+
if (IsGitpod.isGitpod) {
|
|
9
|
+
return [`frame-src 'self' ${GetGitpodPreviewUrl.getGitpodPreviewUrl(3001)} ${GetGitpodPreviewUrl.getGitpodPreviewUrl(3002)}`];
|
|
10
|
+
}
|
|
11
|
+
if (IsElectron.isElectron) {
|
|
12
|
+
return [`frame-src ${Scheme.WebView}:`];
|
|
13
|
+
}
|
|
14
|
+
return [`frame-src 'self' http://localhost:3001 http://localhost:3002`];
|
|
15
|
+
};
|
|
16
|
+
const getManifestSrc = () => {
|
|
17
|
+
if (IsElectron.isElectron) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
return [`manifest-src 'self'`];
|
|
21
|
+
};
|
|
22
|
+
const getFrameAncestors = () => {
|
|
23
|
+
return [`frame-ancestors 'none'`];
|
|
9
24
|
};
|
|
10
25
|
export const value = GetContentSecurityPolicy.getContentSecurityPolicy([
|
|
11
26
|
`default-src 'none'`,
|
|
12
27
|
`font-src 'self'`,
|
|
13
|
-
`img-src 'self' https: data:`,
|
|
28
|
+
`img-src 'self' https: data:`, // TODO maybe disallow https and data images
|
|
14
29
|
`media-src 'self'`,
|
|
15
30
|
`script-src 'self'`,
|
|
16
31
|
`style-src 'self'`,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
: `frame-src 'self' http://localhost:3001 http://localhost:3002`,
|
|
21
|
-
...(IsElectron.isElectron ? [] : [`manifest-src 'self'`]),
|
|
32
|
+
...getFrameAncestors(),
|
|
33
|
+
...getFrameSrc(),
|
|
34
|
+
...getManifestSrc(),
|
|
22
35
|
]);
|
|
@@ -101,6 +101,16 @@ const applyOverrides = async ({ root, commitHash, pathPrefix }) => {
|
|
|
101
101
|
}
|
|
102
102
|
return languages;
|
|
103
103
|
};
|
|
104
|
+
const getWebViews = (extension) => {
|
|
105
|
+
const webViews = [];
|
|
106
|
+
for (const webView of extension.webViews || []) {
|
|
107
|
+
webViews.push({
|
|
108
|
+
...webView,
|
|
109
|
+
path: `${pathPrefix}/${commitHash}/extensions/${webView.path}`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return webViews;
|
|
113
|
+
};
|
|
104
114
|
/**
|
|
105
115
|
* @param {string} dirent
|
|
106
116
|
*/
|
|
@@ -111,6 +121,8 @@ const applyOverrides = async ({ root, commitHash, pathPrefix }) => {
|
|
|
111
121
|
const manifests = await Promise.all(manifestPaths.map(readExtensionManifest));
|
|
112
122
|
const languages = manifests.flatMap(getLanguages);
|
|
113
123
|
await JsonFile.writeJson(Path.join(root, 'dist', commitHash, 'config', 'languages.json'), languages);
|
|
124
|
+
const webViews = manifests.flatMap(getWebViews);
|
|
125
|
+
await JsonFile.writeJson(Path.join(root, 'dist', commitHash, 'config', 'webViews.json'), webViews);
|
|
114
126
|
for (const languageBasicsDirent of languageBasicsDirents) {
|
|
115
127
|
await FileSystem.copy(Path.join(root, 'node_modules', '@lvce-editor', 'server', 'static', commitHash, 'extensions', languageBasicsDirent), Path.join(root, 'dist', commitHash, 'extensions', languageBasicsDirent));
|
|
116
128
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { stat } from 'fs/promises';
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
2
|
import * as GetElectronFileResponseAbsolutePath from '../GetElectronFileResponseAbsolutePath/GetElectronFileResponseAbsolutePath.js';
|
|
3
3
|
import * as GetElectronFileResponseContent from '../GetElectronFileResponseContent/GetElectronFileResponseContent.js';
|
|
4
4
|
import * as GetElectronFileResponseRelativePath from '../GetElectronFileResponseRelativePath/GetElectronFileResponseRelativePath.js';
|
|
@@ -7,27 +7,35 @@ import * as GetHeaders from '../GetHeaders/GetHeaders.js';
|
|
|
7
7
|
import * as GetNotFoundResponse from '../GetNotFoundResponse/GetNotFoundResponse.js';
|
|
8
8
|
import * as GetNotModifiedResponse from '../GetNotModifiedResponse/GetNotModifiedResponse.js';
|
|
9
9
|
import * as GetServerErrorResponse from '../GetServerErrorResponse/GetServerErrorResponse.js';
|
|
10
|
+
import * as HttpHeader from '../HttpHeader/HttpHeader.js';
|
|
10
11
|
import * as HttpStatusCode from '../HttpStatusCode/HttpStatusCode.js';
|
|
11
12
|
import * as IsEnoentError from '../IsEnoentError/IsEnoentError.js';
|
|
12
13
|
import * as Logger from '../Logger/Logger.js';
|
|
14
|
+
// TODO maybe handle app responses and webview responses separately
|
|
15
|
+
// maybe send webview requests directly to preview process
|
|
13
16
|
export const getElectronFileResponse = async (url, request) => {
|
|
14
17
|
try {
|
|
15
18
|
const pathName = GetElectronFileResponseRelativePath.getElectronFileResponseRelativePath(url);
|
|
16
|
-
|
|
19
|
+
let absolutePath = GetElectronFileResponseAbsolutePath.getElectronFileResponseAbsolutePath(pathName);
|
|
17
20
|
let etag;
|
|
21
|
+
// TODO when is there no request?
|
|
18
22
|
if (request) {
|
|
19
|
-
|
|
23
|
+
let stats = await stat(absolutePath);
|
|
24
|
+
if (stats.isDirectory()) {
|
|
25
|
+
absolutePath += '/index.html';
|
|
26
|
+
stats = await stat(absolutePath);
|
|
27
|
+
}
|
|
20
28
|
etag = GetEtag.getEtag(stats);
|
|
21
|
-
if (request.headers[
|
|
29
|
+
if (request.headers[HttpHeader.IfNotMatch] === etag) {
|
|
22
30
|
const headers = GetHeaders.getHeaders(absolutePath, pathName);
|
|
23
31
|
return GetNotModifiedResponse.getNotModifiedResponse(headers);
|
|
24
32
|
}
|
|
25
33
|
}
|
|
26
34
|
const content = await GetElectronFileResponseContent.getElectronFileResponseContent(request, absolutePath, url);
|
|
27
35
|
const headers = GetHeaders.getHeaders(absolutePath, pathName);
|
|
28
|
-
headers[
|
|
36
|
+
headers[HttpHeader.CacheControl] = 'public, max-age=0, must-revalidate';
|
|
29
37
|
if (etag) {
|
|
30
|
-
headers[
|
|
38
|
+
headers[HttpHeader.Etag] = etag;
|
|
31
39
|
}
|
|
32
40
|
return {
|
|
33
41
|
body: content,
|
package/src/parts/GetElectronFileResponseAbsolutePath/GetElectronFileResponseAbsolutePath.js
CHANGED
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import * as Path from '../Path/Path.js';
|
|
5
5
|
import * as Platform from '../Platform/Platform.js';
|
|
6
6
|
import * as Root from '../Root/Root.js';
|
|
7
|
+
// TODO clean up this code
|
|
7
8
|
export const getElectronFileResponseAbsolutePath = (pathName) => {
|
|
8
9
|
// TODO remove if/else in prod (use replacement)
|
|
9
10
|
if (pathName === `/` || pathName.startsWith(`/?`)) {
|
|
@@ -30,5 +31,9 @@ export const getElectronFileResponseAbsolutePath = (pathName) => {
|
|
|
30
31
|
const processExplorerThemeCss = join(tmpdir(), 'process-explorer-theme.css');
|
|
31
32
|
return processExplorerThemeCss;
|
|
32
33
|
}
|
|
34
|
+
// TODO move this to preview process
|
|
35
|
+
if (pathName.startsWith('/home')) {
|
|
36
|
+
return pathName;
|
|
37
|
+
}
|
|
33
38
|
return Path.join(Root.root, 'static', pathName);
|
|
34
39
|
};
|
package/src/parts/GetElectronFileResponseRelativePath/GetElectronFileResponseRelativePath.js
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import * as Platform from '../Platform/Platform.js';
|
|
2
|
+
import * as Scheme from '../Scheme/Scheme.js';
|
|
2
3
|
const { scheme } = Platform;
|
|
3
4
|
const prefix = `${scheme}://-`;
|
|
4
5
|
const prefixLength = prefix.length;
|
|
6
|
+
const webViewPrefix = `${Scheme.WebView}://-`;
|
|
7
|
+
const webViewPrefixLength = webViewPrefix.length;
|
|
5
8
|
export const getElectronFileResponseRelativePath = (requestUrl) => {
|
|
9
|
+
if (requestUrl.startsWith(prefix)) {
|
|
10
|
+
// TODO only support reading from app root and extensions
|
|
11
|
+
// maybe add a separate protocol for extensions (e.g. lvce-remote)
|
|
12
|
+
const decoded = decodeURI(requestUrl);
|
|
13
|
+
const pathName = decoded.slice(prefixLength);
|
|
14
|
+
return pathName;
|
|
15
|
+
}
|
|
16
|
+
if (requestUrl.startsWith(webViewPrefix)) {
|
|
17
|
+
// TODO group this by extension so that
|
|
18
|
+
// extension-a can only access resources in extension-a folder and
|
|
19
|
+
// extension-b can only access resources in extension-b folder
|
|
20
|
+
const decoded = decodeURI(requestUrl);
|
|
21
|
+
const pathName = decoded.slice(webViewPrefixLength);
|
|
22
|
+
return pathName;
|
|
23
|
+
}
|
|
6
24
|
if (requestUrl.startsWith('/')) {
|
|
25
|
+
// TODO this should not be supported anymore and could probably be removed
|
|
7
26
|
return requestUrl;
|
|
8
27
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return pathName;
|
|
28
|
+
console.log({ requestUrl });
|
|
29
|
+
return '';
|
|
12
30
|
};
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import * as HandleIpc from '../HandleIpc/HandleIpc.js';
|
|
2
2
|
import * as IpcParent from '../IpcParent/IpcParent.js';
|
|
3
3
|
import * as IpcParentType from '../IpcParentType/IpcParentType.js';
|
|
4
|
+
import * as IsElectron from '../IsElectron/IsElectron.js';
|
|
5
|
+
import * as Preferences from '../Preferences/Preferences.js';
|
|
4
6
|
import * as PreviewProcessPath from '../PreviewProcessPath/PreviewProcessPath.js';
|
|
7
|
+
const getMethod = (isElectron) => {
|
|
8
|
+
if (isElectron) {
|
|
9
|
+
return IpcParentType.ElectronUtilityProcess;
|
|
10
|
+
}
|
|
11
|
+
return IpcParentType.NodeForkedProcess;
|
|
12
|
+
};
|
|
5
13
|
export const launchPreviewProcess = async () => {
|
|
6
|
-
const
|
|
14
|
+
const preferences = await Preferences.getUserPreferences();
|
|
15
|
+
const customPreviewProcessPath = preferences['develop.previewProcessPath'];
|
|
16
|
+
const previewProcessPath = customPreviewProcessPath || PreviewProcessPath.previewProcessPath;
|
|
17
|
+
const method = getMethod(IsElectron.isElectron);
|
|
7
18
|
const previewProcess = await IpcParent.create({
|
|
8
19
|
method,
|
|
9
|
-
path:
|
|
20
|
+
path: previewProcessPath,
|
|
10
21
|
argv: [],
|
|
11
22
|
stdio: 'inherit',
|
|
12
23
|
name: 'Preview Process',
|
|
@@ -279,8 +279,10 @@ export const getModuleId = (commandId) => {
|
|
|
279
279
|
return ModuleId.FileWatcher;
|
|
280
280
|
case 'Transferrable.transfer':
|
|
281
281
|
return ModuleId.Transferrable;
|
|
282
|
+
case 'WebViewServer.create':
|
|
282
283
|
case 'WebViewServer.start':
|
|
283
284
|
case 'WebViewServer.setHandler':
|
|
285
|
+
case 'WebViewServer.registerProtocol':
|
|
284
286
|
return ModuleId.WebViewServer;
|
|
285
287
|
default:
|
|
286
288
|
throw new CommandNotFoundError(commandId);
|
|
@@ -41,9 +41,9 @@ export const getAppImageName = () => {
|
|
|
41
41
|
export const getSetupName = () => {
|
|
42
42
|
return 'Lvce-Setup';
|
|
43
43
|
};
|
|
44
|
-
export const version = '0.33.
|
|
45
|
-
export const commit = '
|
|
46
|
-
export const date = '2024-
|
|
44
|
+
export const version = '0.33.6';
|
|
45
|
+
export const commit = '0fe4838';
|
|
46
|
+
export const date = '2024-09-01T17:57:05.000Z';
|
|
47
47
|
export const getVersion = () => {
|
|
48
48
|
return version;
|
|
49
49
|
};
|
|
@@ -16,3 +16,7 @@ export const invoke = async (method, ...params) => {
|
|
|
16
16
|
const ipc = await getOrCreate();
|
|
17
17
|
return JsonRpc.invoke(ipc, method, ...params);
|
|
18
18
|
};
|
|
19
|
+
export const invokeAndTransfer = async (method, ...params) => {
|
|
20
|
+
const ipc = await getOrCreate();
|
|
21
|
+
return JsonRpc.invokeAndTransfer(ipc, method, ...params);
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WebView = 'lvce-oss-webview';
|
|
@@ -2,5 +2,7 @@ import * as WebViewServer from '../WebViewServer/WebViewServer.js';
|
|
|
2
2
|
export const name = 'WebViewServer';
|
|
3
3
|
export const Commands = {
|
|
4
4
|
start: WebViewServer.start,
|
|
5
|
+
create: WebViewServer.create,
|
|
5
6
|
setHandler: WebViewServer.setHandler,
|
|
7
|
+
registerProtocol: WebViewServer.registerProtocol,
|
|
6
8
|
};
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import * as PreviewProcess from '../PreviewProcess/PreviewProcess.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import * as ParentIpc from '../ParentIpc/ParentIpc.js';
|
|
3
|
+
import * as GetPortTuple from '../GetPortTuple/GetPortTuple.js';
|
|
4
|
+
export const registerProtocol = async () => {
|
|
5
|
+
// TODO only do this once
|
|
6
|
+
// TODO send messageport to proview process
|
|
7
|
+
// TODO send other messageport to parent process
|
|
8
|
+
console.time('get-ports');
|
|
9
|
+
const { port1, port2 } = await GetPortTuple.getPortTuple();
|
|
10
|
+
console.timeEnd('get-ports');
|
|
11
|
+
console.time('register-protocol');
|
|
12
|
+
await ParentIpc.invokeAndTransfer('ElectronSession.registerWebviewProtocol', port1);
|
|
13
|
+
console.timeEnd('register-protocol');
|
|
14
|
+
console.time('handle-port');
|
|
15
|
+
await PreviewProcess.invokeAndTransfer('HandleElectronMessagePort.handleElectronMessagePort', port2);
|
|
16
|
+
console.timeEnd('handle-port');
|
|
4
17
|
};
|
|
5
|
-
export const
|
|
6
|
-
await PreviewProcess.invoke('WebViewServer.
|
|
18
|
+
export const create = async (previewId) => {
|
|
19
|
+
await PreviewProcess.invoke('WebViewServer.create', previewId);
|
|
20
|
+
};
|
|
21
|
+
export const start = async (previewId, port) => {
|
|
22
|
+
await PreviewProcess.invoke('WebViewServer.start', previewId, port);
|
|
23
|
+
};
|
|
24
|
+
export const setHandler = async (previewId, frameAncestors, webViewRoot) => {
|
|
25
|
+
await PreviewProcess.invoke('WebViewServer.setHandler', previewId, frameAncestors, webViewRoot);
|
|
7
26
|
};
|