@lvce-editor/shared-process 0.99.15 → 0.99.18
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 +3 -3
- package/src/parts/AddCustomPathsToIndexHtml/AddCustomPathsToIndexHtml.js +1 -8
- package/src/parts/BuiltinExtensionsPath/BuiltinExtensionsPath.js +1 -1
- package/src/parts/GetElectronFileResponse/GetElectronFileResponse.js +2 -5
- package/src/parts/GetElectronFileResponseContent/GetElectronFileResponseContent.js +2 -5
- package/src/parts/GetTestRequestResponse/GetTestRequestResponse.js +4 -9
- package/src/parts/HandleMessagePortForExtensionHostHelperProcess/HandleMessagePortForExtensionHostHelperProcess.ipc.js +0 -2
- package/src/parts/HandleMessagePortForExtensionHostHelperProcess/HandleMessagePortForExtensionHostHelperProcess.js +0 -19
- package/src/parts/HandleRequest/HandleRequest.js +0 -5
- package/src/parts/HandleWebSocket/HandleWebSocket.js +2 -36
- package/src/parts/HandleWebSocketForExtensionHostHelperProcess/HandleWebSocketForExtensionHostHelperProcess.js +4 -20
- package/src/parts/Module/Module.js +0 -2
- package/src/parts/ModuleId/ModuleId.js +0 -1
- package/src/parts/ModuleMap/ModuleMap.js +0 -4
- package/src/parts/Platform/Platform.js +3 -3
- package/src/parts/PreloadUrl/PreloadUrl.js +1 -1
- package/src/parts/Workers/Workers.json +2 -0
- package/src/parts/GetWebSocketCapabilityResponse/GetWebSocketCapabilityResponse.js +0 -43
- package/src/parts/IsDocumentNavigation/IsDocumentNavigation.js +0 -4
- package/src/parts/WebSocketCapability/WebSocketCapability.ipc.js +0 -9
- package/src/parts/WebSocketCapability/WebSocketCapability.js +0 -53
- package/src/parts/WebSocketCapabilityRegistry/WebSocketCapabilityRegistry.js +0 -57
- package/src/parts/WebSocketIssuerRegistry/WebSocketIssuerRegistry.js +0 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.99.
|
|
3
|
+
"version": "0.99.18",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@lvce-editor/assert": "1.9.0",
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.99.
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.99.18",
|
|
22
22
|
"@lvce-editor/ipc": "16.10.0",
|
|
23
23
|
"@lvce-editor/json-rpc": "8.6.0",
|
|
24
24
|
"@lvce-editor/jsonc-parser": "1.5.0",
|
|
25
25
|
"@lvce-editor/pretty-error": "2.0.0",
|
|
26
26
|
"@lvce-editor/process-explorer": "3.14.0",
|
|
27
|
-
"@lvce-editor/rpc-registry": "9.
|
|
27
|
+
"@lvce-editor/rpc-registry": "9.48.0",
|
|
28
28
|
"@lvce-editor/verror": "1.7.0",
|
|
29
29
|
"is-object": "^1.0.2",
|
|
30
30
|
"markdown-it": "^15.0.0",
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
export const addCustomPathsToIndexHtml = async (content
|
|
2
|
-
if (Object.keys(additionalConfig).length === 0) {
|
|
1
|
+
export const addCustomPathsToIndexHtml = async (content) => {
|
|
3
2
|
return content
|
|
4
|
-
}
|
|
5
|
-
const stringifiedConfig = JSON.stringify(additionalConfig, null, 2)
|
|
6
|
-
return content.toString().replace(
|
|
7
|
-
'</title>',
|
|
8
|
-
'</title>\n <script type="application/json" id="Config">' + stringifiedConfig + '</script>',
|
|
9
|
-
)
|
|
10
3
|
}
|
|
@@ -3,6 +3,6 @@ import { fileURLToPath } from 'url'
|
|
|
3
3
|
|
|
4
4
|
export const getBuiltinExtensionsPath = () => {
|
|
5
5
|
const staticServerPath = fileURLToPath(import.meta.resolve('@lvce-editor/static-server'))
|
|
6
|
-
const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '
|
|
6
|
+
const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '93dad47', 'extensions')
|
|
7
7
|
return builtinExtensionsPath
|
|
8
8
|
}
|
|
@@ -10,7 +10,6 @@ import * as GetPathEtag from '../GetPathEtag/GetPathEtag.js'
|
|
|
10
10
|
import * as GetServerErrorResponse from '../GetServerErrorResponse/GetServerErrorResponse.js'
|
|
11
11
|
import * as GetTypeScriptSyntaxErrorResponse from '../GetTypeScriptSyntaxErrorResponse/GetTypeScriptSyntaxErrorResponse.js'
|
|
12
12
|
import * as HttpHeader from '../HttpHeader/HttpHeader.js'
|
|
13
|
-
import * as IsDocumentNavigation from '../IsDocumentNavigation/IsDocumentNavigation.js'
|
|
14
13
|
import * as IsEnoentError from '../IsEnoentError/IsEnoentError.js'
|
|
15
14
|
import * as IsTypeScriptSyntaxError from '../IsTypeScriptSyntaxError/IsTypeScriptSyntaxError.js'
|
|
16
15
|
import * as Logger from '../Logger/Logger.js'
|
|
@@ -25,8 +24,6 @@ export const resolveElectronFileUri = (url) => {
|
|
|
25
24
|
// maybe send webview requests directly to preview process
|
|
26
25
|
export const getElectronFileResponse = async (url, request) => {
|
|
27
26
|
try {
|
|
28
|
-
const isRootDocument = url === '/' || url.startsWith('/?')
|
|
29
|
-
const isSecretDocument = isRootDocument && IsDocumentNavigation.isDocumentNavigation(request)
|
|
30
27
|
const pathName = GetElectronFileResponseRelativePath.getElectronFileResponseRelativePath(url)
|
|
31
28
|
let absolutePath = GetElectronFileResponseAbsolutePath.getElectronFileResponseAbsolutePath(pathName)
|
|
32
29
|
let etag
|
|
@@ -45,7 +42,7 @@ export const getElectronFileResponse = async (url, request) => {
|
|
|
45
42
|
preparedContent = await GetElectronFileResponseContent.getElectronFileResponseContent(request, absolutePath, url)
|
|
46
43
|
size = preparedContent.byteLength
|
|
47
44
|
}
|
|
48
|
-
if (
|
|
45
|
+
if (request.headers[HttpHeader.IfNotMatch] === etag) {
|
|
49
46
|
const headers = await GetHeaders.getHeaders(absolutePath, pathName, etag, url, size)
|
|
50
47
|
return GetNotModifiedResponse.getNotModifiedResponse(headers)
|
|
51
48
|
}
|
|
@@ -54,7 +51,7 @@ export const getElectronFileResponse = async (url, request) => {
|
|
|
54
51
|
const size = content.byteLength
|
|
55
52
|
const headers = await GetHeaders.getHeaders(absolutePath, pathName, etag, url, size)
|
|
56
53
|
|
|
57
|
-
headers[HttpHeader.CacheControl] =
|
|
54
|
+
headers[HttpHeader.CacheControl] = 'public, max-age=0, must-revalidate'
|
|
58
55
|
return GetContentResponse.getContentResponse(content, headers)
|
|
59
56
|
} catch (error) {
|
|
60
57
|
if (IsEnoentError.isEnoentError(error)) {
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises'
|
|
2
2
|
import * as AddCustomPathsToIndexHtml from '../AddCustomPathsToIndexHtml/AddCustomPathsToIndexHtml.js'
|
|
3
|
-
import * as IsDocumentNavigation from '../IsDocumentNavigation/IsDocumentNavigation.js'
|
|
4
3
|
import * as Platform from '../Platform/Platform.js'
|
|
5
4
|
import * as ShouldTranspileTypescript from '../ShouldTranspileTypescript/ShouldTranspileTypescript.js'
|
|
6
5
|
import * as TranspileTypeScript from '../TranspileTypeScript/TranspileTypeScript.js'
|
|
7
|
-
import * as WebSocketIssuerRegistry from '../WebSocketIssuerRegistry/WebSocketIssuerRegistry.js'
|
|
8
6
|
|
|
9
7
|
const useCache = false // TODO enable this
|
|
10
8
|
|
|
@@ -25,9 +23,8 @@ export const getElectronFileResponseContent = async (request, absolutePath, url)
|
|
|
25
23
|
content = content.toString().replace(' <link rel="manifest" href="/manifest.json" crossorigin="use-credentials" />\n', '')
|
|
26
24
|
content = await AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(content)
|
|
27
25
|
}
|
|
28
|
-
if (url === '/'
|
|
29
|
-
|
|
30
|
-
content = await AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(content, additionalConfig)
|
|
26
|
+
if (url === '/') {
|
|
27
|
+
content = await AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(content)
|
|
31
28
|
}
|
|
32
29
|
if (typeof content === 'string') {
|
|
33
30
|
content = Buffer.from(content)
|
|
@@ -13,19 +13,13 @@ import * as GetTestPath from '../GetTestPath/GetTestPath.js'
|
|
|
13
13
|
import * as HttpHeader from '../HttpHeader/HttpHeader.js'
|
|
14
14
|
import * as HttpStatusCode from '../HttpStatusCode/HttpStatusCode.js'
|
|
15
15
|
import * as Logger from '../Logger/Logger.js'
|
|
16
|
-
import * as WebSocketIssuerRegistry from '../WebSocketIssuerRegistry/WebSocketIssuerRegistry.js'
|
|
17
|
-
|
|
18
|
-
const getTestPageContent = async (indexHtmlPath) => {
|
|
19
|
-
const body = await readFile(indexHtmlPath, 'utf8')
|
|
20
|
-
const webSocketIssuer = WebSocketIssuerRegistry.create()
|
|
21
|
-
return AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(body, { webSocketIssuer })
|
|
22
|
-
}
|
|
23
16
|
|
|
24
17
|
export const getTestRequestResponse = async (request, indexHtmlPath) => {
|
|
25
18
|
try {
|
|
26
19
|
const pathName = GetPathName.getPathName(request)
|
|
27
20
|
if (pathName === '/tests/_all.html') {
|
|
28
|
-
const
|
|
21
|
+
const body = await readFile(indexHtmlPath, 'utf8')
|
|
22
|
+
const content = await AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(body)
|
|
29
23
|
const headers = {
|
|
30
24
|
[HttpHeader.ContentSecurityPolicy]: ContentSecurityPolicyDocument.value,
|
|
31
25
|
[HttpHeader.ContentType]: 'text/html',
|
|
@@ -36,7 +30,8 @@ export const getTestRequestResponse = async (request, indexHtmlPath) => {
|
|
|
36
30
|
return GetContentResponse.getContentResponse(content, headers)
|
|
37
31
|
}
|
|
38
32
|
if (pathName.endsWith('.html')) {
|
|
39
|
-
const
|
|
33
|
+
const body = await readFile(indexHtmlPath, 'utf8')
|
|
34
|
+
const content = await AddCustomPathsToIndexHtml.addCustomPathsToIndexHtml(body)
|
|
40
35
|
const headers = {
|
|
41
36
|
[HttpHeader.ContentSecurityPolicy]: ContentSecurityPolicyDocument.value,
|
|
42
37
|
[HttpHeader.ContentType]: 'text/html',
|
|
@@ -4,6 +4,4 @@ export const name = 'HandleMessagePortForExtensionHostHelperProcess'
|
|
|
4
4
|
|
|
5
5
|
export const Commands = {
|
|
6
6
|
handleMessagePortForExtensionHostHelperProcess: HandleMessagePortForExtensionHostHelperProcess.handleMessagePortForExtensionHostHelperProcess,
|
|
7
|
-
handlePreloadedMessagePortForExtensionHostHelperProcess:
|
|
8
|
-
HandleMessagePortForExtensionHostHelperProcess.handlePreloadedMessagePortForExtensionHostHelperProcess,
|
|
9
7
|
}
|
|
@@ -23,22 +23,3 @@ export const handleMessagePortForExtensionHostHelperProcess = async (rendererWor
|
|
|
23
23
|
// }
|
|
24
24
|
// rendererWorkerIpc.on('close', cleanup)
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
export const handlePreloadedMessagePortForExtensionHostHelperProcess = async (
|
|
28
|
-
port,
|
|
29
|
-
modulePath,
|
|
30
|
-
) => {
|
|
31
|
-
Assert.object(port)
|
|
32
|
-
Assert.string(modulePath)
|
|
33
|
-
const ipc = await ExtensionHostHelperProcessIpc.create({
|
|
34
|
-
method: IpcParentType.ElectronUtilityProcess,
|
|
35
|
-
})
|
|
36
|
-
HandleIpc.handleIpc(ipc)
|
|
37
|
-
try {
|
|
38
|
-
await JsonRpc.invoke(ipc, 'LoadFile.loadFile', modulePath)
|
|
39
|
-
await JsonRpc.invokeAndTransfer(ipc, 'HandleElectronMessagePort.handleElectronMessagePort', port, IpcId.ExtensionHostWorker)
|
|
40
|
-
} catch (error) {
|
|
41
|
-
ipc.dispose()
|
|
42
|
-
throw error
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { join } from 'path'
|
|
2
2
|
import * as Assert from '../Assert/Assert.js'
|
|
3
3
|
import * as GetElectronFileResponse from '../GetElectronFileResponse/GetElectronFileResponse.js'
|
|
4
|
-
import * as GetWebSocketCapabilityResponse from '../GetWebSocketCapabilityResponse/GetWebSocketCapabilityResponse.js'
|
|
5
4
|
import * as HandleRequestTest from '../HandleRequestTest/HandleRequestTest.js'
|
|
6
5
|
import * as HttpServerResponse from '../HttpServerResponse/HttpServerResponse.js'
|
|
7
6
|
import * as StaticPath from '../StaticPath/StaticPath.js'
|
|
@@ -18,10 +17,6 @@ export const handleRequest = async (socket, request) => {
|
|
|
18
17
|
const indexHtmlPath = join(staticPath, 'index.html')
|
|
19
18
|
return HandleRequestTest.handleRequestTest(socket, request, indexHtmlPath)
|
|
20
19
|
}
|
|
21
|
-
if (request.url.startsWith('/websocket-capabilities/')) {
|
|
22
|
-
const response = GetWebSocketCapabilityResponse.getWebSocketCapabilityResponse(request)
|
|
23
|
-
return HttpServerResponse.send(request, socket, response)
|
|
24
|
-
}
|
|
25
20
|
const fileResponse = await GetElectronFileResponse.getElectronFileResponse(request.url, request)
|
|
26
21
|
HttpServerResponse.send(request, socket, fileResponse)
|
|
27
22
|
}
|
|
@@ -5,29 +5,6 @@ import * as HandleWebSocketModule from '../HandleWebSocketModule/HandleWebSocket
|
|
|
5
5
|
import * as IsAllowedWebSocketOrigin from '../IsAllowedWebSocketOrigin/IsAllowedWebSocketOrigin.js'
|
|
6
6
|
import * as RejectWebSocket from '../RejectWebSocket/RejectWebSocket.js'
|
|
7
7
|
import { VError } from '../VError/VError.js'
|
|
8
|
-
import * as WebSocketCapabilityRegistry from '../WebSocketCapabilityRegistry/WebSocketCapabilityRegistry.js'
|
|
9
|
-
|
|
10
|
-
const capabilityPath = '/websocket/capability'
|
|
11
|
-
|
|
12
|
-
const getCapabilityToken = (message) => {
|
|
13
|
-
const header = message.headers?.['sec-websocket-protocol']
|
|
14
|
-
if (typeof header !== 'string') {
|
|
15
|
-
return ''
|
|
16
|
-
}
|
|
17
|
-
const protocols = header.split(',').map((protocol) => protocol.trim())
|
|
18
|
-
if (!protocols.includes(WebSocketCapabilityRegistry.capabilityProtocol)) {
|
|
19
|
-
return ''
|
|
20
|
-
}
|
|
21
|
-
const capabilityProtocol = protocols.find((protocol) => protocol.startsWith(WebSocketCapabilityRegistry.capabilityProtocolPrefix))
|
|
22
|
-
return capabilityProtocol?.slice(WebSocketCapabilityRegistry.capabilityProtocolPrefix.length) || ''
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const sanitizeProtocols = (message) => {
|
|
26
|
-
message.headers = {
|
|
27
|
-
...message.headers,
|
|
28
|
-
'sec-websocket-protocol': WebSocketCapabilityRegistry.capabilityProtocol,
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
8
|
|
|
32
9
|
export const handleWebSocket = async (handle, message) => {
|
|
33
10
|
try {
|
|
@@ -38,21 +15,10 @@ export const handleWebSocket = async (handle, message) => {
|
|
|
38
15
|
return
|
|
39
16
|
}
|
|
40
17
|
const { url } = message
|
|
41
|
-
|
|
42
|
-
RejectWebSocket.rejectWebSocket(handle)
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
const token = getCapabilityToken(message)
|
|
46
|
-
const capability = WebSocketCapabilityRegistry.consume(token)
|
|
47
|
-
if (!capability) {
|
|
48
|
-
RejectWebSocket.rejectWebSocket(handle)
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
sanitizeProtocols(message)
|
|
52
|
-
const type = capability.target
|
|
18
|
+
const type = GetTypeFromUrl.getTypeFromUrl(url)
|
|
53
19
|
handle.pause()
|
|
54
20
|
const module = HandleWebSocketModule.load(type)
|
|
55
|
-
|
|
21
|
+
module.handleWebSocket(message, handle, type)
|
|
56
22
|
} catch (error) {
|
|
57
23
|
DestroyWebSocket.destroySocket(handle)
|
|
58
24
|
throw new VError(error, `Failed to connect to websocket`)
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import * as
|
|
3
|
-
import * as HandleIpc from '../HandleIpc/HandleIpc.js'
|
|
4
|
-
import * as IpcParentType from '../IpcParentType/IpcParentType.js'
|
|
5
|
-
import * as JsonRpc from '../JsonRpc/JsonRpc.js'
|
|
1
|
+
import * as HandleIncomingIpc from '../HandleIncomingIpc/HandleIncomingIpc.js'
|
|
2
|
+
import * as IpcId from '../IpcId/IpcId.js'
|
|
6
3
|
|
|
7
|
-
export const handleWebSocket =
|
|
8
|
-
|
|
9
|
-
throw new Error('extension helper capability is missing a module path')
|
|
10
|
-
}
|
|
11
|
-
const ipc = await ExtensionHostHelperProcessIpc.create({
|
|
12
|
-
method: IpcParentType.NodeForkedProcess,
|
|
13
|
-
})
|
|
14
|
-
HandleIpc.handleIpc(ipc)
|
|
15
|
-
try {
|
|
16
|
-
await JsonRpc.invoke(ipc, 'LoadFile.loadFile', capability.modulePath)
|
|
17
|
-
await JsonRpc.invokeAndTransfer(ipc, 'HandleWebSocket.handleWebSocket', handle, message)
|
|
18
|
-
} catch (error) {
|
|
19
|
-
ipc.dispose()
|
|
20
|
-
throw error
|
|
21
|
-
}
|
|
4
|
+
export const handleWebSocket = (message, handle) => {
|
|
5
|
+
return HandleIncomingIpc.handleIncomingIpc(IpcId.ExtensionHostHelperProcess, handle, message)
|
|
22
6
|
}
|
|
@@ -154,8 +154,6 @@ export const load = (moduleId) => {
|
|
|
154
154
|
return import('../Terminal/Terminal.ipc.js')
|
|
155
155
|
case ModuleId.TextDocument:
|
|
156
156
|
return import('../TextDocument/TextDocument.ipc.js')
|
|
157
|
-
case ModuleId.WebSocketCapability:
|
|
158
|
-
return import('../WebSocketCapability/WebSocketCapability.ipc.js')
|
|
159
157
|
case ModuleId.WebViewServer:
|
|
160
158
|
return import('../WebViewServer/WebViewServer.ipc.js')
|
|
161
159
|
case ModuleId.Window:
|
|
@@ -302,10 +302,6 @@ export const getModuleId = (commandId) => {
|
|
|
302
302
|
return ModuleId.Terminal
|
|
303
303
|
case 'Transferrable.transfer':
|
|
304
304
|
return ModuleId.Transferrable
|
|
305
|
-
case 'WebSocketCapability.create':
|
|
306
|
-
case 'WebSocketCapability.createExtensionNodeRpc':
|
|
307
|
-
case 'WebSocketCapability.createLegacyExtensionNodeRpc':
|
|
308
|
-
return ModuleId.WebSocketCapability
|
|
309
305
|
case 'WebViewServer.create':
|
|
310
306
|
case 'WebViewServer.registerProtocol':
|
|
311
307
|
case 'WebViewServer.setHandler':
|
|
@@ -61,11 +61,11 @@ export const getSetupName = () => {
|
|
|
61
61
|
return 'Lvce-Setup'
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export const version = '0.99.
|
|
64
|
+
export const version = '0.99.18'
|
|
65
65
|
|
|
66
|
-
export const commit = '
|
|
66
|
+
export const commit = '93dad47'
|
|
67
67
|
|
|
68
|
-
export const date = '2026-08-
|
|
68
|
+
export const date = '2026-08-08T05:53:58.000Z'
|
|
69
69
|
|
|
70
70
|
export const getVersion = () => {
|
|
71
71
|
return version
|
|
@@ -2,5 +2,5 @@ import { join } from 'node:path'
|
|
|
2
2
|
import * as Root from '../Root/Root.js'
|
|
3
3
|
|
|
4
4
|
export const getPreloadUrl = () => {
|
|
5
|
-
return join(Root.root, 'static', '
|
|
5
|
+
return join(Root.root, 'static', '93dad47', 'packages', 'preload', 'dist', 'index.js')
|
|
6
6
|
}
|
|
@@ -652,6 +652,7 @@
|
|
|
652
652
|
{ "source": "state", "name": "platform" }, { "source": "state", "name": "assetDir" }, { "source": "state", "name": "parentUid" }
|
|
653
653
|
] },
|
|
654
654
|
"loadContent": { "name": "SearchExtensions.loadContent", "parameters": [{ "source": "state", "name": "id" }, { "source": "argument", "name": "savedState" }] },
|
|
655
|
+
"handleExtensionsChanged": { "name": "SearchExtensions.handleExtensionsChanged", "parameters": [{ "source": "state", "name": "id" }] },
|
|
655
656
|
"diff": { "name": "SearchExtensions.diff2", "parameters": [{ "source": "state", "name": "id" }] },
|
|
656
657
|
"render": { "name": "SearchExtensions.render3", "parameters": [{ "source": "state", "name": "id" }, { "source": "result", "name": "diff" }] },
|
|
657
658
|
"saveState": { "name": "SearchExtensions.saveState", "parameters": [{ "source": "state", "name": "id" }] },
|
|
@@ -662,6 +663,7 @@
|
|
|
662
663
|
"getMenuEntries": { "name": "SearchExtensions.getMenuEntries2", "parameters": [{ "source": "argument", "name": "args", "spread": true }] },
|
|
663
664
|
"renderEventListeners": { "name": "SearchExtensions.renderEventListeners", "parameters": [] }
|
|
664
665
|
},
|
|
666
|
+
"extraCommands": [{ "name": "handleExtensionsChanged", "method": "handleExtensionsChanged" }],
|
|
665
667
|
"title": "Extensions: Installed",
|
|
666
668
|
"capabilities": { "events": true, "render": true, "resize": true, "rootRender": true }
|
|
667
669
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import * as HttpHeader from '../HttpHeader/HttpHeader.js'
|
|
2
|
-
import * as HttpStatusCode from '../HttpStatusCode/HttpStatusCode.js'
|
|
3
|
-
import * as WebSocketCapability from '../WebSocketCapability/WebSocketCapability.js'
|
|
4
|
-
import * as WebSocketIssuerRegistry from '../WebSocketIssuerRegistry/WebSocketIssuerRegistry.js'
|
|
5
|
-
|
|
6
|
-
const jsonHeaders = {
|
|
7
|
-
[HttpHeader.CacheControl]: 'no-store',
|
|
8
|
-
[HttpHeader.ContentType]: 'application/json; charset=utf-8',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const getResponse = (status, value) => {
|
|
12
|
-
return {
|
|
13
|
-
body: Buffer.from(JSON.stringify(value)),
|
|
14
|
-
init: {
|
|
15
|
-
headers: jsonHeaders,
|
|
16
|
-
status,
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const getBearerToken = (authorization) => {
|
|
22
|
-
if (typeof authorization !== 'string' || !authorization.startsWith('Bearer ')) {
|
|
23
|
-
return ''
|
|
24
|
-
}
|
|
25
|
-
return authorization.slice('Bearer '.length)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const getWebSocketCapabilityResponse = (request) => {
|
|
29
|
-
if (request.method !== 'GET') {
|
|
30
|
-
return getResponse(HttpStatusCode.Forbidden, { error: 'method not allowed' })
|
|
31
|
-
}
|
|
32
|
-
const issuer = getBearerToken(request.headers?.authorization)
|
|
33
|
-
if (!WebSocketIssuerRegistry.isValid(issuer)) {
|
|
34
|
-
return getResponse(HttpStatusCode.Forbidden, { error: 'invalid websocket issuer' })
|
|
35
|
-
}
|
|
36
|
-
const prefix = '/websocket-capabilities/'
|
|
37
|
-
try {
|
|
38
|
-
const target = decodeURIComponent(request.url.slice(prefix.length).split('?')[0])
|
|
39
|
-
return getResponse(HttpStatusCode.Ok, WebSocketCapability.create(target))
|
|
40
|
-
} catch {
|
|
41
|
-
return getResponse(HttpStatusCode.Forbidden, { error: 'websocket target not allowed' })
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as WebSocketCapability from './WebSocketCapability.js'
|
|
2
|
-
|
|
3
|
-
export const name = 'WebSocketCapability'
|
|
4
|
-
|
|
5
|
-
export const Commands = {
|
|
6
|
-
create: WebSocketCapability.create,
|
|
7
|
-
createExtensionNodeRpc: WebSocketCapability.createExtensionNodeRpc,
|
|
8
|
-
createLegacyExtensionNodeRpc: WebSocketCapability.createLegacyExtensionNodeRpc,
|
|
9
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import * as WebSocketCapabilityRegistry from '../WebSocketCapabilityRegistry/WebSocketCapabilityRegistry.js'
|
|
2
|
-
|
|
3
|
-
const allowedTargets = new Set([
|
|
4
|
-
'clipboard-process',
|
|
5
|
-
'file-system-process',
|
|
6
|
-
'process-explorer',
|
|
7
|
-
'search-process',
|
|
8
|
-
'shared-process',
|
|
9
|
-
'terminal-process',
|
|
10
|
-
])
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const createConnectionInfo = (token) => {
|
|
18
|
-
return {
|
|
19
|
-
protocols: WebSocketCapabilityRegistry.getProtocols(token),
|
|
20
|
-
url: '/websocket/capability',
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const create = (target) => {
|
|
25
|
-
if (!allowedTargets.has(target)) {
|
|
26
|
-
throw new Error(`WebSocket target ${target} is not allowed`)
|
|
27
|
-
}
|
|
28
|
-
return createConnectionInfo(WebSocketCapabilityRegistry.create(target))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const createExtensionNodeRpc = (extensionId, rpcId, modulePath) => {
|
|
32
|
-
if (!extensionId || !rpcId || !modulePath) {
|
|
33
|
-
throw new TypeError('extension node rpc capability requires extensionId, rpcId and modulePath')
|
|
34
|
-
}
|
|
35
|
-
return createConnectionInfo(
|
|
36
|
-
WebSocketCapabilityRegistry.create('extension-host-helper-process', {
|
|
37
|
-
extensionId,
|
|
38
|
-
modulePath,
|
|
39
|
-
rpcId,
|
|
40
|
-
}),
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const createLegacyExtensionNodeRpc = (modulePath) => {
|
|
45
|
-
if (!modulePath) {
|
|
46
|
-
throw new TypeError('legacy extension node rpc capability requires a modulePath')
|
|
47
|
-
}
|
|
48
|
-
return createConnectionInfo(
|
|
49
|
-
WebSocketCapabilityRegistry.create('extension-host-helper-process', {
|
|
50
|
-
modulePath,
|
|
51
|
-
}),
|
|
52
|
-
)
|
|
53
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from 'node:crypto'
|
|
2
|
-
|
|
3
|
-
export const capabilityProtocol = 'lvce-rpc'
|
|
4
|
-
export const capabilityProtocolPrefix = 'lvce-capability.'
|
|
5
|
-
export const capabilityTtl = 60_000
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const capabilities = new Map ()
|
|
16
|
-
|
|
17
|
-
const cleanup = (now) => {
|
|
18
|
-
for (const [token, capability] of capabilities) {
|
|
19
|
-
if (capability.expiresAt <= now) {
|
|
20
|
-
capabilities.delete(token)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const create = (target, options = {}) => {
|
|
26
|
-
const now = Date.now()
|
|
27
|
-
cleanup(now)
|
|
28
|
-
const token = randomBytes(32).toString('base64url')
|
|
29
|
-
capabilities.set(token, {
|
|
30
|
-
...options,
|
|
31
|
-
expiresAt: now + capabilityTtl,
|
|
32
|
-
target,
|
|
33
|
-
})
|
|
34
|
-
return token
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export const consume = (token) => {
|
|
38
|
-
const now = Date.now()
|
|
39
|
-
cleanup(now)
|
|
40
|
-
const capability = capabilities.get(token)
|
|
41
|
-
if (!capability) {
|
|
42
|
-
return undefined
|
|
43
|
-
}
|
|
44
|
-
capabilities.delete(token)
|
|
45
|
-
if (capability.expiresAt <= now) {
|
|
46
|
-
return undefined
|
|
47
|
-
}
|
|
48
|
-
return capability
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const getProtocols = (token) => {
|
|
52
|
-
return [capabilityProtocol, `${capabilityProtocolPrefix}${token}`]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export const clear = () => {
|
|
56
|
-
capabilities.clear()
|
|
57
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { randomBytes } from 'node:crypto'
|
|
2
|
-
|
|
3
|
-
export const issuerTtl = 24 * 60 * 60 * 1000
|
|
4
|
-
|
|
5
|
-
const issuers = new Map ()
|
|
6
|
-
|
|
7
|
-
const cleanup = (now) => {
|
|
8
|
-
for (const [issuer, expiresAt] of issuers) {
|
|
9
|
-
if (expiresAt <= now) {
|
|
10
|
-
issuers.delete(issuer)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const create = () => {
|
|
16
|
-
const now = Date.now()
|
|
17
|
-
cleanup(now)
|
|
18
|
-
const issuer = randomBytes(32).toString('base64url')
|
|
19
|
-
issuers.set(issuer, now + issuerTtl)
|
|
20
|
-
return issuer
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const isValid = (issuer) => {
|
|
24
|
-
const now = Date.now()
|
|
25
|
-
cleanup(now)
|
|
26
|
-
const expiresAt = issuers.get(issuer)
|
|
27
|
-
return typeof expiresAt === 'number' && expiresAt > now
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const clear = () => {
|
|
31
|
-
issuers.clear()
|
|
32
|
-
}
|