@lvce-editor/extension-host-helper-process 0.22.0 → 0.22.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-host-helper-process",
3
- "version": "0.22.0",
3
+ "version": "0.22.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -16,13 +16,13 @@
16
16
  "node": ">=18"
17
17
  },
18
18
  "dependencies": {
19
- "@babel/code-frame": "^7.23.5",
19
+ "@lvce-editor/assert": "^1.1.0",
20
+ "@lvce-editor/json-rpc": "^1.0.0",
21
+ "@lvce-editor/pretty-error": "^1.4.0",
20
22
  "@lvce-editor/verror": "^1.1.2",
21
- "clean-stack": "^5.2.0",
23
+ "@lvce-editor/web-socket-server": "^1.1.0",
22
24
  "execa": "^8.0.1",
23
25
  "got": "^13.0.0",
24
- "lines-and-columns": "^2.0.4",
25
- "minimist": "^1.2.8",
26
- "ws": "^8.16.0"
26
+ "minimist": "^1.2.8"
27
27
  }
28
28
  }
@@ -1,71 +1 @@
1
- class AssertionError extends Error {
2
- constructor(message) {
3
- super(message)
4
- this.name = 'AssertionError'
5
- }
6
- }
7
-
8
- const getType = (value) => {
9
- switch (typeof value) {
10
- case 'number':
11
- return 'number'
12
- case 'function':
13
- return 'function'
14
- case 'string':
15
- return 'string'
16
- case 'object':
17
- if (value === null) {
18
- return 'null'
19
- }
20
- if (Array.isArray(value)) {
21
- return 'array'
22
- }
23
- return 'object'
24
- case 'boolean':
25
- return 'boolean'
26
- default:
27
- return 'unknown'
28
- }
29
- }
30
-
31
- export const object = (value) => {
32
- const type = getType(value)
33
- if (type !== 'object') {
34
- throw new AssertionError('expected value to be of type object')
35
- }
36
- }
37
-
38
- export const number = (value) => {
39
- const type = getType(value)
40
- if (type !== 'number') {
41
- throw new AssertionError('expected value to be of type number')
42
- }
43
- }
44
-
45
- export const array = (value) => {
46
- const type = getType(value)
47
- if (type !== 'array') {
48
- throw new AssertionError('expected value to be of type array')
49
- }
50
- }
51
-
52
- export const string = (value) => {
53
- const type = getType(value)
54
- if (type !== 'string') {
55
- throw new AssertionError('expected value to be of type string')
56
- }
57
- }
58
-
59
- export const boolean = (value) => {
60
- const type = getType(value)
61
- if (type !== 'boolean') {
62
- throw new AssertionError('expected value to be of type boolean')
63
- }
64
- }
65
-
66
- export const fn = (value) => {
67
- const type = getType(value)
68
- if (type !== 'function') {
69
- throw new AssertionError('expected value to be of type function')
70
- }
71
- }
1
+ export * from '@lvce-editor/assert'
@@ -1,42 +1 @@
1
- import * as Assert from '../Assert/Assert.js'
2
- import * as Id from '../Id/Id.js'
3
-
4
- export const state = {
5
- callbacks: Object.create(null),
6
- }
7
-
8
- export const registerPromise = () => {
9
- const id = Id.create()
10
- const promise = new Promise((resolve, reject) => {
11
- state.callbacks[id] = {
12
- resolve,
13
- reject,
14
- }
15
- })
16
- return { id, promise }
17
- }
18
-
19
- export const unregister = (id) => {
20
- delete state.callbacks[id]
21
- }
22
-
23
- export const resolve = (id, args) => {
24
- Assert.number(id)
25
- if (!(id in state.callbacks)) {
26
- console.log(args)
27
- console.warn(`callback ${id} may already be disposed`)
28
- return
29
- }
30
- state.callbacks[id].resolve(args)
31
- delete state.callbacks[id]
32
- }
33
-
34
- export const reject = (id, error) => {
35
- Assert.number(id)
36
- if (!(id in state.callbacks)) {
37
- console.warn(`callback ${id} may already be disposed`)
38
- return
39
- }
40
- state.callbacks[id].reject(error)
41
- delete state.callbacks[id]
42
- }
1
+ export { resolve } from '@lvce-editor/json-rpc'
@@ -1,5 +1,6 @@
1
1
  import * as Ajax from '../Ajax/Ajax.js'
2
2
  import * as Exec from '../Exec/Exec.js'
3
+ import * as HandleElectronMessagePort from '../HandleElectronMessagePort/HandleElectronMessagePort.js'
3
4
  import * as HandleWebSocket from '../HandleWebSocket/HandleWebSocket.js'
4
5
  import * as LoadFile from '../LoadFile/LoadFile.js'
5
6
 
@@ -8,4 +9,5 @@ export const commandMap = {
8
9
  'Ajax.getJson': Ajax.getJson,
9
10
  'HandleWebSocket.handleWebSocket': HandleWebSocket.handleWebSocket,
10
11
  'LoadFile.loadFile': LoadFile.loadFile,
12
+ 'HandleElectronMessagePort.handleElectronMessagePort': HandleElectronMessagePort.handleElectronMessagePort,
11
13
  }
@@ -0,0 +1,3 @@
1
+ export const getData = (event) => {
2
+ return event.data
3
+ }
@@ -0,0 +1,10 @@
1
+ export const getUtilityProcessPortData = (event) => {
2
+ const { data, ports } = event
3
+ if (ports.length === 0) {
4
+ return data
5
+ }
6
+ return {
7
+ ...data,
8
+ params: [...ports, ...data.params],
9
+ }
10
+ }
@@ -10,5 +10,4 @@ export const handleElectronMessagePort = async (messagePort) => {
10
10
  messagePort,
11
11
  })
12
12
  HandleIpc.handleIpc(ipc)
13
- messagePort.start()
14
13
  }
@@ -1,12 +1,25 @@
1
- import * as Assert from '../Assert/Assert.js'
2
- import * as Command from '../Command/Command.js'
3
1
  import * as Callback from '../Callback/Callback.js'
4
- import * as HandleJsonRpcMessage from '../HandleJsonRpcMessage/HandleJsonRpcMessage.js'
2
+ import * as Command from '../Command/Command.js'
3
+ import * as JsonRpc from '../JsonRpc/JsonRpc.js'
4
+ import * as PrettyError from '../PrettyError/PrettyError.js'
5
+ import * as PrintPrettyError from '../PrintPrettyError/PrintPrettyError.js'
6
+
7
+ const preparePrettyError = PrettyError.prepare
8
+
9
+ const logError = (error, prettyError) => {
10
+ PrintPrettyError.printPrettyError(prettyError, `[extension-host-helper-process] `)
11
+ }
12
+
13
+ const requiresSocket = () => {
14
+ return false
15
+ }
5
16
 
6
17
  export const handleIpc = (ipc) => {
7
- Assert.object(ipc)
8
- const handleMessage = async (message) => {
9
- return HandleJsonRpcMessage.handleJsonRpcMessage(ipc, message, Command.execute, Callback.resolve)
18
+ const handleMessage = (message) => {
19
+ return JsonRpc.handleJsonRpcMessage(ipc, message, Command.execute, Callback.resolve, preparePrettyError, logError, requiresSocket)
10
20
  }
11
21
  ipc.on('message', handleMessage)
22
+ if (ipc.start) {
23
+ ipc.start()
24
+ }
12
25
  }
@@ -2,17 +2,14 @@ import * as Assert from '../Assert/Assert.js'
2
2
  import * as HandleIpc from '../HandleIpc/HandleIpc.js'
3
3
  import * as IpcChild from '../IpcChild/IpcChild.js'
4
4
  import * as IpcChildType from '../IpcChildType/IpcChildType.js'
5
- import * as WebSocketServer from '../WebSocketServer/WebSocketServer.js'
6
5
 
7
6
  export const handleWebSocket = async (request, handle) => {
8
7
  Assert.object(request)
9
8
  Assert.object(handle)
10
- const webSocket = await WebSocketServer.handleUpgrade(request, handle)
11
- webSocket.pause()
12
9
  const ipc = await IpcChild.listen({
13
10
  method: IpcChildType.WebSocket,
14
- webSocket,
11
+ request,
12
+ handle,
15
13
  })
16
14
  HandleIpc.handleIpc(ipc)
17
- webSocket.resume()
18
15
  }
@@ -1,3 +1,4 @@
1
+ import * as GetUtilityProcessPortData from '../GetUtilityProcessPortData/GetUtilityProcessPortData.js'
1
2
  import { IpcError } from '../IpcError/IpcError.js'
2
3
  import * as IsMessagePortMain from '../IsMessagePortMain/IsMessagePortMain.js'
3
4
 
@@ -8,17 +9,13 @@ export const listen = ({ messagePort }) => {
8
9
  return messagePort
9
10
  }
10
11
 
11
- const getActualData = (event) => {
12
- return event.data
13
- }
14
-
15
12
  export const wrap = (messagePort) => {
16
13
  return {
17
14
  messagePort,
18
15
  on(event, listener) {
19
16
  if (event === 'message') {
20
17
  const wrappedListener = (event) => {
21
- const actualData = getActualData(event)
18
+ const actualData = GetUtilityProcessPortData.getUtilityProcessPortData(event)
22
19
  listener(actualData)
23
20
  }
24
21
  this.messagePort.on(event, wrappedListener)
@@ -35,5 +32,8 @@ export const wrap = (messagePort) => {
35
32
  dispose() {
36
33
  this.messagePort.close()
37
34
  },
35
+ start() {
36
+ this.messagePort.start()
37
+ },
38
38
  }
39
39
  }
@@ -1,3 +1,4 @@
1
+ import * as GetUtilityProcessPortData from '../GetUtilityProcessPortData/GetUtilityProcessPortData.js'
1
2
  import { IpcError } from '../IpcError/IpcError.js'
2
3
 
3
4
  export const listen = () => {
@@ -14,7 +15,17 @@ export const wrap = (parentPort) => {
14
15
  return {
15
16
  parentPort,
16
17
  on(event, listener) {
17
- this.parentPort.on(event, listener)
18
+ if (event === 'message') {
19
+ const wrappedListener = (event) => {
20
+ const actualData = GetUtilityProcessPortData.getUtilityProcessPortData(event)
21
+ listener(actualData)
22
+ }
23
+ this.parentPort.on(event, wrappedListener)
24
+ } else if (event === 'close') {
25
+ this.parentPort.on('close', listener)
26
+ } else {
27
+ throw new Error('unsupported event type')
28
+ }
18
29
  },
19
30
  off(event, listener) {
20
31
  this.parentPort.off(event, listener)
@@ -22,6 +33,9 @@ export const wrap = (parentPort) => {
22
33
  send(message) {
23
34
  this.parentPort.postMessage(message)
24
35
  },
36
+ sendAndTransfer(message, transfer) {
37
+ this.parentPort.postMessage(message, transfer)
38
+ },
25
39
  dispose() {
26
40
  this.parentPort.close()
27
41
  },
@@ -1,16 +1,18 @@
1
1
  import * as GetFirstWebSocketEvent from '../GetFirstWebSocketEvent/GetFirstWebSocketEvent.js'
2
2
  import { IpcError } from '../IpcError/IpcError.js'
3
- import * as IsWebSocket from '../IsWebSocket/IsWebSocket.js'
4
3
  import * as IsWebSocketOpen from '../IsWebSocketOpen/IsWebSocketOpen.js'
5
4
  import * as WebSocketSerialization from '../WebSocketSerialization/WebSocketSerialization.js'
5
+ import * as WebSocketServer from '../WebSocketServer/WebSocketServer.js'
6
6
 
7
- export const listen = async ({ webSocket }) => {
8
- if (!webSocket) {
9
- throw new IpcError('webSocket must be defined')
7
+ export const listen = async ({ request, handle }) => {
8
+ if (!request) {
9
+ throw new IpcError('request must be defined')
10
10
  }
11
- if (!IsWebSocket.isWebSocket(webSocket)) {
12
- throw new IpcError(`webSocket must be of type WebSocket`)
11
+ if (!handle) {
12
+ throw new IpcError('handle must be defined')
13
13
  }
14
+ const webSocket = await WebSocketServer.handleUpgrade(request, handle)
15
+ webSocket.pause()
14
16
  if (!IsWebSocketOpen.isWebSocketOpen(webSocket)) {
15
17
  const { type, event } = await GetFirstWebSocketEvent.getFirstWebSocketEvent(webSocket)
16
18
  console.log({ type, event })
@@ -48,5 +50,8 @@ export const wrap = (webSocket) => {
48
50
  dispose() {
49
51
  this.webSocket.close()
50
52
  },
53
+ start() {
54
+ this.webSocket.resume()
55
+ },
51
56
  }
52
57
  }
@@ -1 +1 @@
1
- export const ErrorMethodNotFound = -32601
1
+ export * from '@lvce-editor/json-rpc'
@@ -1,55 +1 @@
1
- import { codeFrameColumns } from '@babel/code-frame'
2
- import { readFileSync } from 'node:fs'
3
- import { fileURLToPath } from 'node:url'
4
- import * as CleanStack from '../CleanStack/CleanStack.js'
5
-
6
- const getActualPath = (fileUri) => {
7
- if (fileUri.startsWith('file://')) {
8
- return fileURLToPath(fileUri)
9
- }
10
- return fileUri
11
- }
12
-
13
- export const prepare = (error) => {
14
- const message = error.message
15
- if (error && error.cause) {
16
- const cause = error.cause()
17
- if (cause) {
18
- error = cause
19
- }
20
- }
21
- const lines = CleanStack.cleanStack(error.stack)
22
- const file = lines[0]
23
- let codeFrame = ''
24
- if (error.codeFrame) {
25
- codeFrame = error.codeFrame
26
- } else if (file) {
27
- let match = file.match(/\((.*):(\d+):(\d+)\)$/)
28
- if (!match) {
29
- match = file.match(/at (.*):(\d+):(\d+)$/)
30
- }
31
- if (match) {
32
- const [_, path, line, column] = match
33
- const actualPath = getActualPath(path)
34
- const rawLines = readFileSync(actualPath, 'utf-8')
35
- const location = {
36
- start: {
37
- line: Number.parseInt(line),
38
- column: Number.parseInt(column),
39
- },
40
- }
41
-
42
- codeFrame = codeFrameColumns(rawLines, location)
43
- }
44
- }
45
- const relevantStack = lines.slice(1).join('\n')
46
- return {
47
- message,
48
- stack: relevantStack,
49
- codeFrame,
50
- code: error.code,
51
- type: error.constructor.name,
52
- stderr: error.stderr,
53
- stdout: error.stdout,
54
- }
55
- }
1
+ export { prepare, prepareJsonError } from '@lvce-editor/pretty-error'
@@ -1,21 +1 @@
1
- import { Buffer } from 'node:buffer'
2
- import * as _ws from 'ws'
3
-
4
- // workaround for jest or node bug
5
- const WebSocketServer = _ws.WebSocketServer
6
- ? _ws.WebSocketServer
7
- : // @ts-ignore
8
- _ws.default.WebSocketServer
9
-
10
- const webSocketServer = new WebSocketServer({
11
- noServer: true,
12
- })
13
-
14
- export const handleUpgrade = (request, socket) => {
15
- return new Promise((resolve, reject) => {
16
- const upgradeCallback = (ws) => {
17
- resolve(ws)
18
- }
19
- webSocketServer.handleUpgrade(request, socket, Buffer.alloc(0), upgradeCallback)
20
- })
21
- }
1
+ export * from '@lvce-editor/web-socket-server'
@@ -1,97 +0,0 @@
1
- import * as SplitLines from '../SplitLines/SplitLines.js'
2
-
3
- const RE_AT = /^\s+at/
4
- const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/
5
- const RE_OBJECT_AS = /^\s*at (async )?Object\.\w+ \[as ([\w\.]+)\]/
6
- const RE_GET_RESPONSE = /^\s*at async getResponse/
7
- const RE_WEBSOCKET_HANDLE_MESSAGE = /^\s*at async WebSocket.handleMessage/
8
- const RE_EXECUTE_COMMAND_ASYNC = /^\s*at executeCommandAsync/
9
- const RE_HANDLE_OTHER_MESSAGES_FROM_MESSAGE_PORT = /^\s*at async MessagePort\.handleOtherMessagesFromMessagePort/
10
- const RE_ASSERT = /^\s*at .*\/Assert\.js/
11
-
12
- const isInternalLine = (line) => {
13
- return line.includes('node:') || RE_AT_PROMISE_INDEX.test(line) || line.includes('node_modules/ws')
14
- }
15
-
16
- const isRelevantLine = (line) => {
17
- return !isInternalLine(line)
18
- }
19
-
20
- const isApplicationUsefulLine = (line, index) => {
21
- if (index === 0) {
22
- if (RE_ASSERT.test(line)) {
23
- return false
24
- }
25
- return true
26
- }
27
- if (RE_GET_RESPONSE.test(line)) {
28
- return false
29
- }
30
- if (RE_WEBSOCKET_HANDLE_MESSAGE.test(line)) {
31
- return false
32
- }
33
- if (RE_EXECUTE_COMMAND_ASYNC.test(line)) {
34
- return false
35
- }
36
- if (RE_HANDLE_OTHER_MESSAGES_FROM_MESSAGE_PORT.test(line)) {
37
- return false
38
- }
39
- return true
40
- }
41
-
42
- const isNormalStackLine = (line) => {
43
- return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line)
44
- }
45
-
46
- const cleanLine = (line) => {
47
- if (line.startsWith(' at exports.')) {
48
- return ' at ' + line.slice(' at exports.'.length)
49
- }
50
- if (line.startsWith(' at async exports.')) {
51
- return ' at async ' + line.slice(' at async exports.'.length)
52
- }
53
- if (line.startsWith(' at async Module.')) {
54
- return ' at async ' + line.slice(' at async Module.'.length)
55
- }
56
- if (line.startsWith(' at Module.')) {
57
- return ' at ' + line.slice(' at Module.'.length)
58
- }
59
- const objectMatch = line.match(RE_OBJECT_AS)
60
- if (objectMatch) {
61
- const rest = line.slice(objectMatch[0].length)
62
- if (objectMatch[1]) {
63
- return ' at ' + objectMatch[1] + objectMatch[2] + rest
64
- }
65
- return ' at ' + objectMatch[2] + rest
66
- }
67
- return line
68
- }
69
-
70
- const getDetails = (lines) => {
71
- const index = lines.findIndex(isNormalStackLine)
72
- return {
73
- custom: lines.slice(0, index),
74
- actualStack: lines.slice(index).map(cleanLine),
75
- }
76
- }
77
-
78
- const RE_PATH_1 = /^\/(.*)(\d+)$/
79
-
80
- const mergeCustom = (custom, relevantStack) => {
81
- if (custom.length === 0) {
82
- return relevantStack
83
- }
84
- const firstLine = custom[0]
85
- if (RE_PATH_1.test(firstLine)) {
86
- return [` at ${firstLine}`, ...relevantStack]
87
- }
88
- return relevantStack
89
- }
90
-
91
- export const cleanStack = (stack) => {
92
- const lines = SplitLines.splitLines(stack)
93
- const { custom, actualStack } = getDetails(lines)
94
- const relevantStack = actualStack.filter(isRelevantLine).filter(isApplicationUsefulLine)
95
- const merged = mergeCustom(custom, relevantStack)
96
- return merged
97
- }
@@ -1,33 +0,0 @@
1
- import * as JsonRpcErrorCode from '../JsonRpcErrorCode/JsonRpcErrorCode.js'
2
- import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
3
- import * as PrettyError from '../PrettyError/PrettyError.js'
4
- import * as PrintPrettyError from '../PrintPrettyError/PrintPrettyError.js'
5
-
6
- export const getErrorResponse = (message, error) => {
7
- if (error && error instanceof Error && error.message && error.message.startsWith('method not found')) {
8
- return {
9
- jsonrpc: JsonRpcVersion.Two,
10
- id: message.id,
11
- error: {
12
- code: JsonRpcErrorCode.MethodNotFound,
13
- message: error.message,
14
- data: error.stack,
15
- },
16
- }
17
- }
18
- const prettyError = PrettyError.prepare(error)
19
- PrintPrettyError.printPrettyError(prettyError, `[extension-host-helper-process] `)
20
- return {
21
- jsonrpc: JsonRpcVersion.Two,
22
- id: message.id,
23
- error: {
24
- code: JsonRpcErrorCode.Custom,
25
- message: prettyError.message,
26
- data: {
27
- stack: prettyError.stack,
28
- codeFrame: prettyError.codeFrame,
29
- type: prettyError.type,
30
- },
31
- },
32
- }
33
- }
@@ -1,11 +0,0 @@
1
- import * as GetErrorResponse from '../GetErrorResponse/GetErrorResponse.js'
2
- import * as GetSuccessResponse from '../GetSuccessResponse/GetSuccessResponse.js'
3
-
4
- export const getResponse = async (message, execute) => {
5
- try {
6
- const result = await execute(message.method, ...message.params)
7
- return GetSuccessResponse.getSuccessResponse(message, result)
8
- } catch (error) {
9
- return GetErrorResponse.getErrorResponse(message, error)
10
- }
11
- }
@@ -1,9 +0,0 @@
1
- import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
2
-
3
- export const getSuccessResponse = (message, result) => {
4
- return {
5
- jsonrpc: JsonRpcVersion.Two,
6
- id: message.id,
7
- result: result ?? null,
8
- }
9
- }
@@ -1,2 +0,0 @@
1
- export const MethodNotFound = -32601
2
- export const Custom = -32001
@@ -1 +0,0 @@
1
- export const Two = '2.0'