@lvce-editor/shared-process 0.115.21 → 0.115.23

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.115.21",
3
+ "version": "0.115.23",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -1,3 +1,4 @@
1
+ import * as UpdateLog from '../UpdateLog/UpdateLog.js'
1
2
  import * as AutoUpdater from './AutoUpdater.js'
2
3
 
3
4
  export const Commands = {
@@ -6,4 +7,5 @@ export const Commands = {
6
7
  'AutoUpdater.getPlatform': AutoUpdater.getPlatform,
7
8
  'AutoUpdater.restartMacUpdate': AutoUpdater.restartMacUpdate,
8
9
  'AutoUpdater.stageMacUpdate': AutoUpdater.stageMacUpdate,
10
+ 'AutoUpdater.writeLog': UpdateLog.write,
9
11
  }
@@ -1,11 +1,9 @@
1
- import { spawn } from 'node:child_process'
2
1
  import * as Assert from '../Assert/Assert.js'
3
2
  import * as Download from '../Download/Download.js'
4
- import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
5
- import * as GetFirstSpawnedProcessEvent from '../GetFirstSpawnedProcessEvent/GetFirstSpawnedProcessEvent.js'
6
3
  import * as GetNsisUpdateArgs from '../GetNsisUpdateArgs/GetNsisUpdateArgs.js'
7
4
  import * as GetNsisDownloadPath from '../GetNsisUpdateDownloadPath/GetNsisUpdateDownloadPath.js'
8
5
  import * as GetWindowsNsisDownloadUrl from '../GetWindowsNsisDownloadUrl/GetWindowsNsisDownloadUrl.js'
6
+ import * as LaunchDetachedUpdate from '../LaunchDetachedUpdate/LaunchDetachedUpdate.js'
9
7
  import * as Logger from '../Logger/Logger.js'
10
8
  import * as Platform from '../Platform/Platform.js'
11
9
  import * as UpdateState from '../UpdateState/UpdateState.js'
@@ -49,15 +47,8 @@ export const installAndRestart = async (downloadPath) => {
49
47
  const args = GetNsisUpdateArgs.getNsisUpdateArgs()
50
48
  Logger.info(`[shared-process] spawning nsis update: ${downloadPath}`)
51
49
  UpdateState.set(UpdateStateType.Updating)
52
- const child = spawn(downloadPath, args, {
53
- detached: true,
54
- stdio: 'inherit',
55
- })
56
- const { event, type } = await GetFirstSpawnedProcessEvent.getFirstSpawnedProcessEvent(child)
57
- if (type === FirstNodeWorkerEventType.Error) {
58
- throw new Error(`Child process error: ${event}`)
59
- }
60
- Logger.info(`[shared-process] finished nsis update`)
50
+ await LaunchDetachedUpdate.launch(downloadPath, args)
51
+ Logger.info(`[shared-process] handed off nsis update`)
61
52
  } catch (error) {
62
53
  throw new VError(error, `Failed to install nsis update`)
63
54
  }
@@ -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', '5dceee7', 'extensions')
6
+ const builtinExtensionsPath = join(staticServerPath, '..', '..', 'static', '05a51a8', 'extensions')
7
7
  return builtinExtensionsPath
8
8
  }
@@ -1,5 +1,6 @@
1
1
  import * as childProcess from 'child_process'
2
2
  import { fileURLToPath } from 'url'
3
+ import * as LaunchDetachedUpdate from '../LaunchDetachedUpdate/LaunchDetachedUpdate.js'
3
4
 
4
5
  /**
5
6
  *
@@ -7,7 +8,13 @@ import { fileURLToPath } from 'url'
7
8
  * @param {string[]} args
8
9
  * @returns
9
10
  */
10
- export const exec = async (uri, args) => {
11
+ export const exec = async (uri, args, options = {}) => {
11
12
  const path = fileURLToPath(uri)
13
+ // The update worker requests a detached NSIS installer. Waiting synchronously
14
+ // ties it to the application that the installer must close and replace.
15
+ if (options.detached) {
16
+ await LaunchDetachedUpdate.launch(path, args)
17
+ return
18
+ }
12
19
  childProcess.execFileSync(path, args)
13
20
  }
@@ -0,0 +1,32 @@
1
+ import { spawn } from 'node:child_process'
2
+ import { closeSync } from 'node:fs'
3
+ import * as UpdateLog from '../UpdateLog/UpdateLog.js'
4
+
5
+ export const launch = async (path, args) => {
6
+ UpdateLog.write(`Launching installer ${JSON.stringify({ args, path })}`)
7
+ const output = UpdateLog.openOutput()
8
+ try {
9
+ await new Promise ((resolve, reject) => {
10
+ const child = spawn(path, args, {
11
+ detached: true,
12
+ stdio: ['ignore', output, output],
13
+ windowsHide: true,
14
+ })
15
+ child.once('error', (error) => {
16
+ UpdateLog.writeSafe(`Installer launch failed: ${error.stack || error.message}`)
17
+ reject(error)
18
+ })
19
+ child.once('spawn', () => {
20
+ UpdateLog.writeSafe(`Installer started pid=${child.pid}; installation outcome is not yet known`)
21
+ child.unref()
22
+ resolve()
23
+ })
24
+ // Available while this process is alive. Absence of this entry is not success.
25
+ child.once('exit', (code, signal) => {
26
+ UpdateLog.writeSafe(`Installer exited pid=${child.pid} code=${code} signal=${signal}`)
27
+ })
28
+ })
29
+ } finally {
30
+ closeSync(output)
31
+ }
32
+ }
@@ -1,6 +1,8 @@
1
1
  import { Console } from 'node:console'
2
- import { createWriteStream } from 'node:fs'
3
- import { tmpdir } from 'node:os'
2
+ import { createWriteStream, mkdirSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+ import * as PlatformPaths from '../PlatformPaths/PlatformPaths.js'
4
6
 
5
7
  // TODO mock this module when used in unit tests
6
8
 
@@ -12,8 +14,10 @@ const state = {
12
14
  }
13
15
 
14
16
  const createConsole = () => {
15
- const logFile = `${tmpdir()}/log-shared-process.txt`
16
- const writeStream = createWriteStream(logFile)
17
+ const directory = fileURLToPath(PlatformPaths.getLogsDir())
18
+ mkdirSync(directory, { recursive: true })
19
+ const logFile = join(directory, 'log-shared-process.txt')
20
+ const writeStream = createWriteStream(logFile, { flags: 'a' })
17
21
  const logger = new Console(writeStream)
18
22
  return logger
19
23
  }
@@ -12,6 +12,7 @@ export const getModuleId = (commandId) => {
12
12
  case 'AutoUpdater.getPlatform':
13
13
  case 'AutoUpdater.restartMacUpdate':
14
14
  case 'AutoUpdater.stageMacUpdate':
15
+ case 'AutoUpdater.writeLog':
15
16
  return ModuleId.AutoUpdater
16
17
  case 'AutoUpdaterAppImage.downloadUpdate':
17
18
  case 'AutoUpdaterAppImage.installAndRestart':
@@ -56,11 +56,11 @@ export const getSetupName = () => {
56
56
  return 'Lvce-Setup'
57
57
  }
58
58
 
59
- export const version = '0.115.21'
59
+ export const version = '0.115.23'
60
60
 
61
- export const commit = '5dceee7'
61
+ export const commit = '05a51a8'
62
62
 
63
- export const date = '2026-09-19T10:45:09.000Z'
63
+ export const date = '2026-09-19T11:10:55.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', '5dceee7', 'packages', 'preload', 'dist', 'index.js')
5
+ return join(Root.root, 'static', '05a51a8', 'packages', 'preload', 'dist', 'index.js')
6
6
  }
@@ -0,0 +1,28 @@
1
+ import { appendFileSync, mkdirSync, openSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import * as PlatformPaths from '../PlatformPaths/PlatformPaths.js'
5
+
6
+ export const getPath = () => {
7
+ const directory = fileURLToPath(PlatformPaths.getLogsDir())
8
+ mkdirSync(directory, { recursive: true })
9
+ return join(directory, 'log-updates.txt')
10
+ }
11
+
12
+ // Synchronous appends ensure the last handoff/error is on disk before shutdown.
13
+ export const write = (message) => {
14
+ const path = getPath()
15
+ const line = `${new Date().toISOString()} [updates pid=${process.pid}] ${message.replaceAll('\n', '\\n').replaceAll('\r', '\\r')}\n`
16
+ appendFileSync(path, line)
17
+ appendFileSync(join(fileURLToPath(PlatformPaths.getLogsDir()), 'log-shared-process.txt'), line)
18
+ }
19
+
20
+ export const openOutput = () => openSync(getPath(), 'a')
21
+
22
+ export const writeSafe = (message) => {
23
+ try {
24
+ write(message)
25
+ } catch (error) {
26
+ console.error('Failed to persist update diagnostics', error)
27
+ }
28
+ }
@@ -1,3 +0,0 @@
1
- export const Exit = 1
2
- export const Error = 2
3
- export const Message = 3
@@ -1,23 +0,0 @@
1
- import * as Promises from '../Promises/Promises.js'
2
-
3
- export const getFirstEvent = (eventEmitter, eventMap) => {
4
- const { promise, resolve } = Promises.withResolvers()
5
- const listenerMap = Object.create(null)
6
- const cleanup = (value) => {
7
- for (const event of Object.keys(eventMap)) {
8
- eventEmitter.off(event, listenerMap[event])
9
- }
10
- resolve(value)
11
- }
12
- for (const [event, type] of Object.entries(eventMap)) {
13
- const listener = (event) => {
14
- cleanup({
15
- event,
16
- type,
17
- })
18
- }
19
- eventEmitter.on(event, listener)
20
- listenerMap[event] = listener
21
- }
22
- return promise
23
- }
@@ -1,9 +0,0 @@
1
- import * as FirstNodeWorkerEventType from '../FirstNodeWorkerEventType/FirstNodeWorkerEventType.js'
2
- import * as GetFirstEvent from '../GetFirstEvent/GetFirstEvent.js'
3
-
4
- export const getFirstSpawnedProcessEvent = (childProcess) => {
5
- return GetFirstEvent.getFirstEvent(childProcess, {
6
- error: FirstNodeWorkerEventType.Error,
7
- exit: FirstNodeWorkerEventType.Exit,
8
- })
9
- }
@@ -1,19 +0,0 @@
1
- export const withResolvers = () => {
2
- /**
3
- * @type {any}
4
- */
5
- let _resolve
6
- /**
7
- * @type {any}
8
- */
9
- let _reject
10
- const promise = new Promise((resolve, reject) => {
11
- _resolve = resolve
12
- _reject = reject
13
- })
14
- return {
15
- promise,
16
- reject: _reject,
17
- resolve: _resolve,
18
- }
19
- }