@lvce-editor/shared-process 0.118.8 → 0.118.9

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.118.8",
3
+ "version": "0.118.9",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -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', 'c5e72ea', 'extensions')
6
+ const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', 'e8da65c', 'extensions')
7
7
  return builtinExtensionsPath
8
8
  }
@@ -40,11 +40,13 @@ export const handleIncomingIpc = async (ipcId, handle, message) => {
40
40
  if (!ipcAndResponse) {
41
41
  return
42
42
  }
43
- const { response, target } = ipcAndResponse
43
+ const { complete, release, response, target } = ipcAndResponse
44
44
  const error = await ApplyIncomingIpcResponse.applyIncomingIpcResponse(target, response, ipcId)
45
+ complete?.()
45
46
  if (!error) {
46
47
  return
47
48
  }
49
+ release?.()
48
50
  if (ipcId === IpcId.ProcessExplorer) {
49
51
  ProcessExplorer.decreaseRefCount()
50
52
  }
@@ -1,4 +1,5 @@
1
1
  export const handleIncomingIpcMessagePort = async (module, handle, message) => {
2
+ if (module.connectMessagePort) return module.connectMessagePort(handle, message)
2
3
  const response = module.upgradeMessagePort(handle, message)
3
4
  const target = await module.targetMessagePort(handle, message)
4
5
  return {
@@ -1,4 +1,5 @@
1
1
  export const handleIncomingIpcWebSocket = async (module, handle, message) => {
2
+ if (module.connectWebSocket) return module.connectWebSocket(handle, message)
2
3
  const response = module.upgradeWebSocket(handle, message)
3
4
  const target = await module.targetWebSocket(handle, message)
4
5
  return {
@@ -19,8 +19,31 @@ export const targetMessagePort = () => {
19
19
 
20
20
  export const upgradeMessagePort = (port) => {
21
21
  return {
22
- method: 'HandleElectronMessagePort.handleElectronMessagePort',
22
+ method: 'HandleElectronMessagePort.handleTerminalMessagePort',
23
23
  params: [port],
24
24
  type: 'send',
25
25
  }
26
26
  }
27
+
28
+ const connect = async (handle, message, webSocket) => {
29
+ const lease = PtyHost.acquire(webSocket ? IpcParentType.NodeForkedProcess : IpcParentType.ElectronUtilityProcess)
30
+ const forwarding = PtyHost.acquire(webSocket ? IpcParentType.NodeForkedProcess : IpcParentType.ElectronUtilityProcess)
31
+ try {
32
+ const target = await lease.promise
33
+ const response = webSocket ? upgradeWebSocket(handle, message) : upgradeMessagePort(handle)
34
+ response.params.push(lease.id)
35
+ return {
36
+ complete: () => PtyHost.release(forwarding.id),
37
+ release: () => PtyHost.release(lease.id),
38
+ response,
39
+ target,
40
+ }
41
+ } catch (error) {
42
+ PtyHost.release(lease.id)
43
+ PtyHost.release(forwarding.id)
44
+ throw error
45
+ }
46
+ }
47
+
48
+ export const connectMessagePort = (handle, message) => connect(handle, message, false)
49
+ export const connectWebSocket = (handle, message) => connect(handle, message, true)
@@ -2,7 +2,7 @@ import * as IpcId from '../IpcId/IpcId.js'
2
2
  import * as IsElectron from '../IsElectron/IsElectron.js'
3
3
  import * as LaunchProcess from '../LaunchProcess/LaunchProcess.js'
4
4
  import * as PtyHostPath from '../PtyHostPath/PtyHostPath.js'
5
- import * as PtyHostState from '../PtyHostState/PtyHostState.js'
5
+ import * as ShutdownTerminalProcess from '../ShutdownTerminalProcess/ShutdownTerminalProcess.js'
6
6
 
7
7
  export const launchPtyHost = async (method) => {
8
8
  const ipc = await LaunchProcess.launchProcess({
@@ -12,6 +12,6 @@ export const launchPtyHost = async (method) => {
12
12
  settingName: 'develop.ptyHostPath',
13
13
  targetRpcId: IpcId.TerminalProcess,
14
14
  })
15
- PtyHostState.state.ipc = ipc
15
+ ipc.dispose = () => ShutdownTerminalProcess.shutdownTerminalProcess(ipc)
16
16
  return ipc
17
17
  }
@@ -140,6 +140,8 @@ export const load = (moduleId) => {
140
140
  return import('../ProcessExplorer/ProcessExplorer.ipc.js')
141
141
  case ModuleId.ProcessId:
142
142
  return import('../ProcessId/ProcessId.ipc.js')
143
+ case ModuleId.PtyHost:
144
+ return import('../PtyHost/PtyHost.ipc.js')
143
145
  case ModuleId.RebuildNodePty:
144
146
  return import('../RebuildNodePty/RebuildNodePty.ipc.js')
145
147
  case ModuleId.RecentlyOpened:
@@ -83,3 +83,4 @@ export const HandleMessagePortForFileWatcherExplorer = 95
83
83
  export const RemoteCli = 96
84
84
  export const BrowserFind = 97
85
85
  export const ShellCommand = 98
86
+ export const PtyHost = 99
@@ -287,6 +287,8 @@ export const getModuleId = (commandId) => {
287
287
  case 'ProcessId.getMainProcessId':
288
288
  case 'ProcessId.getSharedProcessId':
289
289
  return ModuleId.ProcessId
290
+ case 'PtyHost.release':
291
+ return ModuleId.PtyHost
290
292
  case 'RebuildNodePty.rebuildNodePty':
291
293
  return ModuleId.RebuildNodePty
292
294
  case 'RecentlyOpened.addPath':
@@ -56,11 +56,11 @@ export const getSetupName = () => {
56
56
  return 'Lvce-Setup'
57
57
  }
58
58
 
59
- export const version = '0.118.8'
59
+ export const version = '0.118.9'
60
60
 
61
- export const commit = 'c5e72ea'
61
+ export const commit = 'e8da65c'
62
62
 
63
- export const date = '2026-09-27T18:12:47.000Z'
63
+ export const date = '2026-09-27T21:31:28.000Z'
64
64
 
65
65
  export const getVersion = () => {
66
66
  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', 'c5e72ea', 'packages', 'preload', 'dist', 'index.js')
5
+ return join(Root.root, 'static', 'e8da65c', 'packages', 'preload', 'dist', 'index.js')
6
6
  }
@@ -0,0 +1,7 @@
1
+ import * as PtyHost from './PtyHost.js'
2
+
3
+ export const name = 'PtyHost'
4
+
5
+ export const Commands = {
6
+ release: PtyHost.release,
7
+ }
@@ -3,29 +3,75 @@ import * as JsonRpc from '../JsonRpc/JsonRpc.js'
3
3
  import * as LaunchPtyHost from '../LaunchPtyHost/LaunchPtyHost.js'
4
4
  import * as PtyHostState from '../PtyHostState/PtyHostState.js'
5
5
 
6
- export const getOrCreate = (method = IpcParentType.NodeForkedProcess) => {
7
- if (!PtyHostState.state.ptyHostPromise) {
8
- PtyHostState.state.ptyHostPromise = LaunchPtyHost.launchPtyHost(method)
6
+
7
+
8
+
9
+
10
+ let current
11
+ let nextId = 0
12
+ let retiring
13
+ const connections = new Map ()
14
+
15
+ const getGeneration = (method) => {
16
+ if (current) return current
17
+ const generation = {
18
+ connections: new Set(),
19
+ promise: retiring ? retiring.then(() => LaunchPtyHost.launchPtyHost(method)) : LaunchPtyHost.launchPtyHost(method),
9
20
  }
10
- return PtyHostState.state.ptyHostPromise
21
+ current = generation
22
+ PtyHostState.state.ptyHostPromise = generation.promise
23
+ void generation.promise.then(
24
+ (ipc) => {
25
+ if (current === generation) PtyHostState.state.ipc = ipc
26
+ },
27
+ () => {
28
+ if (current === generation) detach()
29
+ },
30
+ )
31
+ return generation
32
+ }
33
+
34
+ const detach = () => {
35
+ current = undefined
36
+ PtyHostState.state.ipc = undefined
37
+ PtyHostState.state.ptyHostPromise = undefined
11
38
  }
12
39
 
13
- export const getCurrentInstance = () => {
14
- return PtyHostState.state.ipc
40
+ export const getOrCreate = (method = IpcParentType.NodeForkedProcess) => {
41
+ return getGeneration(method).promise
15
42
  }
16
43
 
44
+ export const acquire = (method) => {
45
+ const generation = getGeneration(method)
46
+ const id = ++nextId
47
+ generation.connections.add(id)
48
+ connections.set(id, generation)
49
+ return { id, promise: generation.promise }
50
+ }
51
+
52
+ export const release = (id) => {
53
+ const generation = connections.get(id)
54
+ if (!generation) return
55
+ connections.delete(id)
56
+ generation.connections.delete(id)
57
+ if (generation.connections.size) return
58
+ if (current === generation) detach()
59
+ retiring = generation.promise.then((ipc) => ipc.dispose(), () => {})
60
+ // Preserve rejection for the next acquisition while avoiding an unhandled rejection.
61
+ void retiring.catch(() => {})
62
+ }
63
+
64
+ export const getCurrentInstance = () => PtyHostState.state.ipc
65
+
17
66
  export const disposeAll = () => {
18
- if (PtyHostState.state.ipc) {
19
- PtyHostState.state.ipc.removeAllListeners()
20
- if (PtyHostState.state.ipc) {
21
- PtyHostState.state.ipc.dispose()
22
- PtyHostState.state.ipc = undefined
23
- }
24
- PtyHostState.state.ptyHostState = /* None */ 0
25
- PtyHostState.state.send = (message) => {
26
- PtyHostState.state.pendingMessages.push(message)
27
- }
28
- }
67
+ const generation = current
68
+ detach()
69
+ if (!generation) return
70
+ for (const id of generation.connections) connections.delete(id)
71
+ generation.connections.clear()
72
+ retiring = generation.promise.then((ipc) => ipc.dispose(), () => {})
73
+ // Preserve rejection for the next acquisition while avoiding an unhandled rejection.
74
+ void retiring.catch(() => {})
29
75
  }
30
76
 
31
77
  export const invoke = (method, ...params) => {
@@ -9,7 +9,6 @@ const supportsPartialIpcHandling = (ipcId) => {
9
9
  case IpcId.EmbedsProcess:
10
10
  case IpcId.FileWatcherExplorer:
11
11
  case IpcId.ProcessExplorer:
12
- case IpcId.TerminalProcess:
13
12
  return true
14
13
  default:
15
14
  return false
@@ -0,0 +1,26 @@
1
+ export const shutdownTerminalProcess = (ipc) => {
2
+ return new Promise((resolve, reject) => {
3
+ const removeListener = () => {
4
+ if (ipc.removeEventListener) ipc.removeEventListener('close', onClose)
5
+ else ipc.off('close', onClose)
6
+ }
7
+ const onClose = () => {
8
+ clearTimeout(timer)
9
+ removeListener()
10
+ resolve()
11
+ }
12
+ const timer = setTimeout(() => {
13
+ removeListener()
14
+ reject(new Error('Terminal process did not exit after shutdown'))
15
+ }, 10_000)
16
+ if (ipc.addEventListener) ipc.addEventListener('close', onClose)
17
+ else ipc.on('close', onClose)
18
+ try {
19
+ ipc.send({ jsonrpc: '2.0', method: 'TerminalProcess.dispose', params: [] })
20
+ } catch (error) {
21
+ clearTimeout(timer)
22
+ removeListener()
23
+ reject(error)
24
+ }
25
+ })
26
+ }
@@ -1638,6 +1638,55 @@
1638
1638
  "renderComparison": "emptyCommands"
1639
1639
  }
1640
1640
  },
1641
+ {
1642
+ "id": "workersView",
1643
+ "fileName": "workersViewMain.js",
1644
+ "contentSecurityPolicy": ["default-src 'none'"],
1645
+ "defaultPath": "/packages/renderer-worker/node_modules/@lvce-editor/workers-view/dist/workersViewMain.js",
1646
+ "productionPath": "/packages/workers-view/dist/workersViewMain.js",
1647
+ "settingName": "develop.workersViewPath",
1648
+ "viewlet": {
1649
+ "name": "Workers",
1650
+ "title": "Workers",
1651
+ "state": {
1652
+ "idKey": "uid",
1653
+ "fields": ["uri", "x", "y", "width", "height"],
1654
+ "contextFields": ["platform", "assetDir"],
1655
+ "defaults": { "title": "Workers" }
1656
+ },
1657
+ "commandPrefix": "Workers",
1658
+ "methods": {
1659
+ "create": {
1660
+ "name": "Workers.create",
1661
+ "parameters": [
1662
+ { "source": "state", "name": "uid" }, { "source": "state", "name": "uri" }, { "source": "state", "name": "x" },
1663
+ { "source": "state", "name": "y" }, { "source": "state", "name": "width" }, { "source": "state", "name": "height" },
1664
+ { "source": "state", "name": "platform" }, { "source": "state", "name": "assetDir" }
1665
+ ]
1666
+ },
1667
+ "loadContent": { "name": "Workers.loadContent", "parameters": [{ "source": "state", "name": "uid" }] },
1668
+ "refresh": { "name": "Workers.refresh", "parameters": [{ "source": "state", "name": "uid" }] },
1669
+ "diff": { "name": "Workers.diff2", "parameters": [{ "source": "state", "name": "uid" }] },
1670
+ "render": {
1671
+ "name": "Workers.render2",
1672
+ "parameters": [{ "source": "state", "name": "uid" }, { "source": "result", "name": "diff" }]
1673
+ },
1674
+ "dispose": { "name": "Workers.dispose", "parameters": [{ "source": "state", "name": "uid" }] },
1675
+ "resize": {
1676
+ "name": "Workers.resize",
1677
+ "parameters": [
1678
+ { "source": "state", "name": "uid" },
1679
+ { "source": "argument", "name": "dimensions", "index": "width" },
1680
+ { "source": "argument", "name": "dimensions", "index": "height" }
1681
+ ]
1682
+ },
1683
+ "getCommandIds": { "name": "Workers.getCommandIds", "parameters": [] },
1684
+ "renderEventListeners": { "name": "Workers.renderEventListeners", "parameters": [] }
1685
+ },
1686
+ "capabilities": { "directRender": true, "events": true, "render": true, "resize": true, "rootRender": true },
1687
+ "renderComparison": "emptyCommands"
1688
+ }
1689
+ },
1641
1690
  {
1642
1691
  "id": "secretsView",
1643
1692
  "fileName": "secretsViewWorkerMain.js",