@lvce-editor/shared-process 0.32.1 → 0.32.2
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/CreateWebViewServerHandler/CreateWebViewServerHandler.js +60 -17
- package/src/parts/GetAppWindowOptions/GetAppWindowOptions.js +1 -1
- package/src/parts/ModuleId/ModuleId.js +1 -0
- package/src/parts/ModuleMap/ModuleMap.js +2 -0
- package/src/parts/Platform/Platform.js +3 -3
- package/src/parts/PreviewInjectedCode/PreviewInjectedCode.js +74 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.2",
|
|
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.32.
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.32.2",
|
|
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",
|
|
@@ -4,6 +4,8 @@ import { pipeline } from 'node:stream/promises';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import * as GetContentSecurityPolicy from '../GetContentSecurityPolicy/GetContentSecurityPolicy.js';
|
|
6
6
|
import * as SetHeaders from '../SetHeaders/SetHeaders.js';
|
|
7
|
+
import * as PreviewInjectedCode from '../PreviewInjectedCode/PreviewInjectedCode.js';
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
7
9
|
const getPathName = (request) => {
|
|
8
10
|
const { pathname } = new URL(request.url || '', `https://${request.headers.host}`);
|
|
9
11
|
return pathname;
|
|
@@ -29,8 +31,61 @@ const textMimeType = {
|
|
|
29
31
|
const getContentType = (filePath) => {
|
|
30
32
|
return textMimeType[extname(filePath)] || 'text/plain';
|
|
31
33
|
};
|
|
34
|
+
const injectPreviewScript = (html) => {
|
|
35
|
+
const injectedCode = `<script type="module" src="/preview-injected.js"></script>\n`;
|
|
36
|
+
const titleEndIndex = html.indexOf('</title>');
|
|
37
|
+
const newHtml = html.slice(0, titleEndIndex + '</title>'.length) + '\n' + injectedCode + html.slice(titleEndIndex);
|
|
38
|
+
return newHtml;
|
|
39
|
+
};
|
|
40
|
+
const handleIndexHtml = async (response, filePath, frameAncestors) => {
|
|
41
|
+
try {
|
|
42
|
+
const csp = GetContentSecurityPolicy.getContentSecurityPolicy([`default-src 'none'`, `script-src 'self'`, `frame-ancestors ${frameAncestors}`]);
|
|
43
|
+
const contentType = getContentType(filePath);
|
|
44
|
+
const content = await readFile(filePath, 'utf8');
|
|
45
|
+
SetHeaders.setHeaders(response, {
|
|
46
|
+
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
47
|
+
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
48
|
+
'Content-Security-Policy': csp,
|
|
49
|
+
'Content-Type': contentType,
|
|
50
|
+
});
|
|
51
|
+
const newContent = injectPreviewScript(content);
|
|
52
|
+
response.end(newContent);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error(`[preview-server] ${error}`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const handleOther = async (response, filePath) => {
|
|
59
|
+
try {
|
|
60
|
+
const contentType = getContentType(filePath);
|
|
61
|
+
// TODO figure out which of these headers are actually needed
|
|
62
|
+
SetHeaders.setHeaders(response, {
|
|
63
|
+
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
64
|
+
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
65
|
+
'Access-Control-Allow-Origin': '*',
|
|
66
|
+
'Content-Type': contentType,
|
|
67
|
+
});
|
|
68
|
+
await pipeline(createReadStream(filePath), response);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(error);
|
|
72
|
+
response.end(`[preview-server] ${error}`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const handlePreviewInjected = (response) => {
|
|
76
|
+
try {
|
|
77
|
+
const injectedCode = PreviewInjectedCode.injectedCode;
|
|
78
|
+
const contentType = getContentType('/test/file.js');
|
|
79
|
+
SetHeaders.setHeaders(response, {
|
|
80
|
+
'Content-Type': contentType,
|
|
81
|
+
});
|
|
82
|
+
response.end(injectedCode);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.error(`[preview-server] ${error}`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
32
88
|
export const createHandler = (frameAncestors, webViewRoot) => {
|
|
33
|
-
const csp = GetContentSecurityPolicy.getContentSecurityPolicy([`default-src 'none'`, `script-src 'self'`, `frame-ancestors ${frameAncestors}`]);
|
|
34
89
|
const handleRequest = async (request, response) => {
|
|
35
90
|
let pathName = getPathName(request);
|
|
36
91
|
if (pathName === '/') {
|
|
@@ -38,25 +93,13 @@ export const createHandler = (frameAncestors, webViewRoot) => {
|
|
|
38
93
|
}
|
|
39
94
|
const filePath = fileURLToPath(`file://${webViewRoot}${pathName}`);
|
|
40
95
|
const isHtml = filePath.endsWith('index.html');
|
|
41
|
-
const contentType = getContentType(filePath);
|
|
42
96
|
if (isHtml) {
|
|
43
|
-
|
|
44
|
-
'Cross-Origin-Resource-Policy': 'cross-origin',
|
|
45
|
-
'Cross-Origin-Embedder-Policy': 'require-corp',
|
|
46
|
-
'Content-Security-Policy': csp,
|
|
47
|
-
'Content-Type': contentType,
|
|
48
|
-
});
|
|
97
|
+
return handleIndexHtml(response, filePath, frameAncestors);
|
|
49
98
|
}
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
});
|
|
99
|
+
if (filePath.endsWith('preview-injected.js')) {
|
|
100
|
+
return handlePreviewInjected(response);
|
|
58
101
|
}
|
|
59
|
-
|
|
102
|
+
return handleOther(response, filePath);
|
|
60
103
|
};
|
|
61
104
|
return handleRequest;
|
|
62
105
|
};
|
|
@@ -6,7 +6,7 @@ export const getAppWindowOptions = (preferences, screenWidth, screenHeight) => {
|
|
|
6
6
|
const titleBarStyle = titleBarPreference === 'custom' ? 'hidden' : undefined;
|
|
7
7
|
const zoomLevelPreference = preferences['window.zoomLevel'];
|
|
8
8
|
const zoomLevel = zoomLevelPreference;
|
|
9
|
-
const windowControlsOverlayPreference = (Platform.isWindows || Platform.isMacOs) && preferences['window.controlsOverlay.enabled'];
|
|
9
|
+
const windowControlsOverlayPreference = (Platform.isWindows || Platform.isMacOs || Platform.isLinux) && preferences['window.controlsOverlay.enabled'];
|
|
10
10
|
const titleBarOverlay = windowControlsOverlayPreference
|
|
11
11
|
? {
|
|
12
12
|
color: '#1e2324',
|
|
@@ -277,6 +277,8 @@ export const getModuleId = (commandId) => {
|
|
|
277
277
|
return ModuleId.HandleMessagePortForSearchProcess;
|
|
278
278
|
case 'FileWatcher.watch':
|
|
279
279
|
return ModuleId.FileWatcher;
|
|
280
|
+
case 'Transferrable.transfer':
|
|
281
|
+
return ModuleId.Transferrable;
|
|
280
282
|
case 'WebViewServer.start':
|
|
281
283
|
case 'WebViewServer.setHandler':
|
|
282
284
|
return ModuleId.WebViewServer;
|
|
@@ -41,9 +41,9 @@ export const getAppImageName = () => {
|
|
|
41
41
|
export const getSetupName = () => {
|
|
42
42
|
return 'Lvce-Setup';
|
|
43
43
|
};
|
|
44
|
-
export const version = '0.32.
|
|
45
|
-
export const commit = '
|
|
46
|
-
export const date = '2024-08-
|
|
44
|
+
export const version = '0.32.2';
|
|
45
|
+
export const commit = '93e00a3';
|
|
46
|
+
export const date = '2024-08-20T21:05:50.000Z';
|
|
47
47
|
export const getVersion = () => {
|
|
48
48
|
return version;
|
|
49
49
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const injectedCode = `
|
|
2
|
+
let commandMap = {}
|
|
3
|
+
let port
|
|
4
|
+
const callbacks = Object.create(null)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const isJsonRpcResponse = message => {
|
|
8
|
+
return 'result' in message || 'error' in message
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const handleMessage = async (event) => {
|
|
12
|
+
const message = event.data
|
|
13
|
+
if(isJsonRpcResponse(message)){
|
|
14
|
+
const fn = callbacks[message.id]
|
|
15
|
+
fn(message.result)
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
const { method, params } = message
|
|
19
|
+
const fn = commandMap[method]
|
|
20
|
+
if(!fn){
|
|
21
|
+
throw new Error("command not found \${method}")
|
|
22
|
+
}
|
|
23
|
+
const result = await fn(...params)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const handleFirstMessage = (event) => {
|
|
27
|
+
const message = event.data
|
|
28
|
+
port = message.params[0]
|
|
29
|
+
port.onmessage = handleMessage
|
|
30
|
+
port.postMessage('ready')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
window.addEventListener('message', handleFirstMessage, {
|
|
34
|
+
once: true,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const withResolvers = () => {
|
|
38
|
+
let _resolve
|
|
39
|
+
const promise = new Promise(resolve => {
|
|
40
|
+
_resolve = resolve
|
|
41
|
+
})
|
|
42
|
+
return {
|
|
43
|
+
resolve: _resolve,
|
|
44
|
+
promise
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const registerPromise = () => {
|
|
49
|
+
const id = 1
|
|
50
|
+
const {resolve, promise} = withResolvers()
|
|
51
|
+
callbacks[id] = { resolve }
|
|
52
|
+
return {
|
|
53
|
+
id, promise
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
globalThis.lvceRpc = (value) => {
|
|
58
|
+
commandMap = value
|
|
59
|
+
return {
|
|
60
|
+
async invoke(method, ...params){
|
|
61
|
+
const {id, promise } = registerPromise()
|
|
62
|
+
port.postMessage({
|
|
63
|
+
jsonrpc: '2.0',
|
|
64
|
+
id,
|
|
65
|
+
method,
|
|
66
|
+
params
|
|
67
|
+
})
|
|
68
|
+
const response = await promise
|
|
69
|
+
// TODO unwrap jsonrpc result
|
|
70
|
+
return response
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
`;
|