@lvce-editor/shared-process 0.106.4 → 0.107.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/shared-process",
3
- "version": "0.106.4",
3
+ "version": "0.107.0",
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.9.0",
21
- "@lvce-editor/extension-host-helper-process": "0.106.4",
21
+ "@lvce-editor/extension-host-helper-process": "0.107.0",
22
22
  "@lvce-editor/ipc": "16.12.0",
23
23
  "@lvce-editor/json-rpc": "8.7.0",
24
24
  "@lvce-editor/jsonc-parser": "1.5.0",
@@ -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', '71bebb6', 'extensions')
6
+ const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '64c8cbf', 'extensions')
7
7
  return builtinExtensionsPath
8
8
  }
@@ -0,0 +1,15 @@
1
+ import * as HandleIpc from '../HandleIpc/HandleIpc.js'
2
+ import * as IpcParent from '../IpcParent/IpcParent.js'
3
+ import * as ResolveExtensionNodeProcess from '../ResolveExtensionNodeProcess/ResolveExtensionNodeProcess.js'
4
+
5
+ export const create = async ({ extensionId, method, rpcId } ) => {
6
+ const { name, path } = await ResolveExtensionNodeProcess.resolveExtensionNodeProcess(extensionId, rpcId)
7
+ const ipc = await IpcParent.create({
8
+ execArgv: [],
9
+ method,
10
+ name,
11
+ path,
12
+ })
13
+ HandleIpc.handleIpc(ipc)
14
+ return ipc
15
+ }
@@ -0,0 +1,7 @@
1
+ import * as HandleMessagePortForExtensionNodeProcess from './HandleMessagePortForExtensionNodeProcess.js'
2
+
3
+ export const name = 'HandleMessagePortForExtensionNodeProcess'
4
+
5
+ export const Commands = {
6
+ handleMessagePortForExtensionNodeProcess: HandleMessagePortForExtensionNodeProcess.handleMessagePortForExtensionNodeProcess,
7
+ }
@@ -0,0 +1,35 @@
1
+ import * as Assert from '../Assert/Assert.js'
2
+ import * as ExtensionNodeProcessIpc from '../ExtensionNodeProcessIpc/ExtensionNodeProcessIpc.js'
3
+ import * as IpcParentType from '../IpcParentType/IpcParentType.js'
4
+ import * as JsonRpc from '../JsonRpc/JsonRpc.js'
5
+
6
+ export const handleMessagePortForExtensionNodeProcess = async (
7
+ rendererWorkerIpc,
8
+ port,
9
+ extensionId,
10
+ rpcId,
11
+ ) => {
12
+ Assert.object(port)
13
+ Assert.string(extensionId)
14
+ Assert.string(rpcId)
15
+ const ipc = await ExtensionNodeProcessIpc.create({
16
+ extensionId,
17
+ method: IpcParentType.ElectronUtilityProcess,
18
+ rpcId,
19
+ })
20
+ const dispose = () => {
21
+ ipc.dispose()
22
+ }
23
+ const removeRendererCloseListener = () => {
24
+ rendererWorkerIpc.off('close', dispose)
25
+ }
26
+ rendererWorkerIpc.on('close', dispose)
27
+ ipc.on('close', removeRendererCloseListener)
28
+ try {
29
+ await JsonRpc.invokeAndTransfer(ipc, 'NodeRpcProcess.handleElectronMessagePort', port)
30
+ } catch (error) {
31
+ removeRendererCloseListener()
32
+ ipc.dispose()
33
+ throw error
34
+ }
35
+ }
@@ -0,0 +1,23 @@
1
+ import * as ExtensionNodeProcessIpc from '../ExtensionNodeProcessIpc/ExtensionNodeProcessIpc.js'
2
+ import * as IpcParentType from '../IpcParentType/IpcParentType.js'
3
+ import * as JsonRpc from '../JsonRpc/JsonRpc.js'
4
+
5
+ export const handleWebSocket = async (message, handle) => {
6
+ const url = new URL(message.url, 'http://localhost')
7
+ const extensionId = url.searchParams.get('extensionId')
8
+ const rpcId = url.searchParams.get('rpcId')
9
+ if (!extensionId || !rpcId) {
10
+ throw new Error('Remote extension node process request is incomplete')
11
+ }
12
+ const ipc = await ExtensionNodeProcessIpc.create({
13
+ extensionId,
14
+ method: IpcParentType.NodeForkedProcess,
15
+ rpcId,
16
+ })
17
+ try {
18
+ await JsonRpc.invokeAndTransfer(ipc, 'NodeRpcProcess.handleWebSocket', handle, message)
19
+ } catch (error) {
20
+ ipc.dispose()
21
+ throw error
22
+ }
23
+ }
@@ -1,5 +1,6 @@
1
1
  import * as HandleWebSocketForClipBoardProcess from '../HandleWebSocketForClipBoardProcess/HandleWebSocketForClipBoardProcess.js'
2
2
  import * as HandleWebSocketForExtensionHostHelperProcess from '../HandleWebSocketForExtensionHostHelperProcess/HandleWebSocketForExtensionHostHelperProcess.js'
3
+ import * as HandleWebSocketForExtensionNodeProcess from '../HandleWebSocketForExtensionNodeProcess/HandleWebSocketForExtensionNodeProcess.js'
3
4
  import * as HandleWebSocketForFileSystemProcess from '../HandleWebSocketForFileSystemProcess/HandleWebSocketForFileSystemProcess.js'
4
5
  import * as HandleWebSocketForProcessExplorer from '../HandleWebSocketForProcessExplorer/HandleWebSocketForProcessExplorer.js'
5
6
  import * as HandleWebSocketForSearchProcess from '../HandleWebSocketForSearchProcess/HandleWebSocketForSearchProcess.js'
@@ -18,6 +19,8 @@ export const load = (protocol) => {
18
19
  return HandleWebSocketForClipBoardProcess
19
20
  case ProtocolType.ExtensionHostHelperProcess:
20
21
  return HandleWebSocketForExtensionHostHelperProcess
22
+ case ProtocolType.ExtensionNodeProcess:
23
+ return HandleWebSocketForExtensionNodeProcess
21
24
  case ProtocolType.FileSystemProcess:
22
25
  return HandleWebSocketForFileSystemProcess
23
26
  case ProtocolType.ProcessExplorer:
@@ -88,6 +88,8 @@ export const load = (moduleId) => {
88
88
  return import('../HandleMessagePortForEmbedsProcess/HandleMessagePortForEmbedsProcess.ipc.js')
89
89
  case ModuleId.HandleMessagePortForExtensionHostHelperProcess:
90
90
  return import('../HandleMessagePortForExtensionHostHelperProcess/HandleMessagePortForExtensionHostHelperProcess.ipc.js')
91
+ case ModuleId.HandleMessagePortForExtensionNodeProcess:
92
+ return import('../HandleMessagePortForExtensionNodeProcess/HandleMessagePortForExtensionNodeProcess.ipc.js')
91
93
  case ModuleId.HandleMessagePortForFileSystemProcess:
92
94
  return import('../HandleMessagePortForFileSystemProcess/HandleMessagePortForFileSystemProcess.ipc.js')
93
95
  case ModuleId.HandleMessagePortForProcessExplorer:
@@ -82,3 +82,4 @@ export const SendMessagePortToMainProcess = 88
82
82
  export const SecretStorage = 89
83
83
  export const FirefoxCookieImport = 91
84
84
  export const IpcTrace = 92
85
+ export const HandleMessagePortForExtensionNodeProcess = 93
@@ -184,6 +184,8 @@ export const getModuleId = (commandId) => {
184
184
  case 'HandleMessagePortForExtensionHostHelperProcess.handleMessagePortForExtensionHostHelperProcess':
185
185
  case 'HandleMessagePortForExtensionHostHelperProcess.handlePreloadedMessagePortForExtensionHostHelperProcess':
186
186
  return ModuleId.HandleMessagePortForExtensionHostHelperProcess
187
+ case 'HandleMessagePortForExtensionNodeProcess.handleMessagePortForExtensionNodeProcess':
188
+ return ModuleId.HandleMessagePortForExtensionNodeProcess
187
189
  case 'HandleMessagePortForFileSystemProcess.handleMessagePortForFileSystemProcess':
188
190
  return ModuleId.HandleMessagePortForFileSystemProcess
189
191
  case 'HandleMessagePortForProcessExplorer.handleMessagePortForProcessExplorer':
@@ -61,11 +61,11 @@ export const getSetupName = () => {
61
61
  return 'Lvce-Setup'
62
62
  }
63
63
 
64
- export const version = '0.106.4'
64
+ export const version = '0.107.0'
65
65
 
66
- export const commit = '71bebb6'
66
+ export const commit = '64c8cbf'
67
67
 
68
- export const date = '2026-08-22T16:15:27.000Z'
68
+ export const date = '2026-08-22T16:38:17.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', '71bebb6', 'packages', 'preload', 'dist', 'index.js')
5
+ return join(Root.root, 'static', '64c8cbf', 'packages', 'preload', 'dist', 'index.js')
6
6
  }
@@ -1,5 +1,6 @@
1
1
  export const ExtensionHost = 'extension-host'
2
2
  export const ExtensionHostHelperProcess = 'extension-host-helper-process'
3
+ export const ExtensionNodeProcess = 'extension-node-process'
3
4
  export const SearchProcess = 'search-process'
4
5
  export const ProcessExplorer = 'process-explorer'
5
6
  export const FileSystemProcess = 'file-system-process'
@@ -11,6 +11,7 @@ const METHODS_THAT_REQUIRE_SOCKET = new Set([
11
11
  'IncrementalTextSearch.start',
12
12
  'ElectronApplicationMenu.setItems',
13
13
  'HandleMessagePortForExtensionHostHelperProcess.handleMessagePortForExtensionHostHelperProcess',
14
+ 'HandleMessagePortForExtensionNodeProcess.handleMessagePortForExtensionNodeProcess',
14
15
  'ElectronBrowserView.createBrowserView',
15
16
  'ElectronWebContentsView.createWebContentsView',
16
17
  'FileWatcher.dispose',
@@ -0,0 +1,55 @@
1
+ import { readFile, realpath } from 'node:fs/promises'
2
+ import path from 'node:path'
3
+ import * as ExtensionManagement from '../ExtensionManagement/ExtensionManagement.js'
4
+
5
+ const idRegex = /^[A-Za-z0-9][A-Za-z0-9._-]*$/
6
+ const schemeRegex = /^[A-Za-z][A-Za-z\d+.-]*:/
7
+
8
+ const isInside = (parent, child) => child === parent || child.startsWith(`${parent}${path.sep}`)
9
+
10
+ const validateId = (value, name) => {
11
+ if (!idRegex.test(value)) {
12
+ throw new Error(`Invalid extension node process ${name}`)
13
+ }
14
+ }
15
+
16
+ const getExtension = async (extensionId) => {
17
+ const extensions = await ExtensionManagement.getExtensions()
18
+ const extension = extensions.find((candidate) => candidate?.id === extensionId)
19
+ if (!extension || typeof extension.path !== 'string') {
20
+ throw new Error(`Extension ${extensionId} is not installed`)
21
+ }
22
+ return extension
23
+ }
24
+
25
+
26
+
27
+
28
+
29
+
30
+ export const resolveExtensionNodeProcess = async (extensionId, rpcId) => {
31
+ validateId(extensionId, 'extension id')
32
+ validateId(rpcId, 'rpc id')
33
+ const extension = await getExtension(extensionId)
34
+ const extensionRoot = await realpath(extension.path)
35
+ const manifestPath = await realpath(path.join(extensionRoot, 'extension.json'))
36
+ if (!isInside(extensionRoot, manifestPath)) {
37
+ throw new Error('Extension manifest escapes the extension root')
38
+ }
39
+ const manifest = JSON.parse(await readFile(manifestPath, 'utf8'))
40
+ const rpc = manifest.rpc?.find((candidate) => candidate?.id === rpcId)
41
+ if (!rpc || rpc.type !== 'node-process' || typeof rpc.url !== 'string') {
42
+ throw new Error(`Node process ${rpcId} is not declared by extension ${extensionId}`)
43
+ }
44
+ if (!rpc.url || path.isAbsolute(rpc.url) || path.win32.isAbsolute(rpc.url) || schemeRegex.test(rpc.url)) {
45
+ throw new Error(`Node process ${rpcId} must use a relative url`)
46
+ }
47
+ const processPath = await realpath(path.resolve(extensionRoot, rpc.url))
48
+ if (!isInside(extensionRoot, processPath)) {
49
+ throw new Error('Extension node process path escapes the extension root')
50
+ }
51
+ return {
52
+ name: `Extension ${extensionId}: ${typeof rpc.name === 'string' && rpc.name ? rpc.name : rpcId}`,
53
+ path: processPath,
54
+ }
55
+ }