@lvce-editor/file-system-process 1.1.0 → 2.0.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.
Files changed (2) hide show
  1. package/dist/index.js +1269 -5
  2. package/package.json +2 -6
package/dist/index.js CHANGED
@@ -1,19 +1,113 @@
1
1
  import * as fs from 'node:fs/promises';
2
2
  import * as os from 'node:os';
3
3
  import { fileURLToPath } from 'node:url';
4
- import { string } from '@lvce-editor/assert';
5
- import { VError } from '@lvce-editor/verror';
6
4
  import { join } from 'node:path';
7
5
  import { existsSync } from 'node:fs';
8
- import { NodeWebSocketRpcClient, ElectronMessagePortRpcClient, ElectronUtilityProcessRpcClient, NodeWorkerRpcClient, NodeForkedProcessRpcClient } from '@lvce-editor/rpc';
9
- import { invoke as invoke$1 } from '@lvce-editor/json-rpc';
10
6
  import _trash from 'trash';
7
+ import { Buffer } from 'node:buffer';
8
+
9
+ class AssertionError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = 'AssertionError';
13
+ }
14
+ }
15
+ const getType = value => {
16
+ switch (typeof value) {
17
+ case 'number':
18
+ return 'number';
19
+ case 'function':
20
+ return 'function';
21
+ case 'string':
22
+ return 'string';
23
+ case 'object':
24
+ if (value === null) {
25
+ return 'null';
26
+ }
27
+ if (Array.isArray(value)) {
28
+ return 'array';
29
+ }
30
+ return 'object';
31
+ case 'boolean':
32
+ return 'boolean';
33
+ default:
34
+ return 'unknown';
35
+ }
36
+ };
37
+ const object = value => {
38
+ const type = getType(value);
39
+ if (type !== 'object') {
40
+ throw new AssertionError('expected value to be of type object');
41
+ }
42
+ };
43
+ const string = value => {
44
+ const type = getType(value);
45
+ if (type !== 'string') {
46
+ throw new AssertionError('expected value to be of type string');
47
+ }
48
+ };
11
49
 
12
50
  const Utf8 = 'utf8';
13
51
 
14
52
  const ENOENT = 'ENOENT';
15
53
  const EXDEV = 'EXDEV';
16
54
 
55
+ const normalizeLine = line => {
56
+ if (line.startsWith('Error: ')) {
57
+ return line.slice('Error: '.length);
58
+ }
59
+ if (line.startsWith('VError: ')) {
60
+ return line.slice('VError: '.length);
61
+ }
62
+ return line;
63
+ };
64
+ const getCombinedMessage = (error, message) => {
65
+ const stringifiedError = normalizeLine(`${error}`);
66
+ if (message) {
67
+ return `${message}: ${stringifiedError}`;
68
+ }
69
+ return stringifiedError;
70
+ };
71
+ const NewLine$2 = '\n';
72
+ const getNewLineIndex$1 = (string, startIndex = undefined) => {
73
+ return string.indexOf(NewLine$2, startIndex);
74
+ };
75
+ const mergeStacks = (parent, child) => {
76
+ if (!child) {
77
+ return parent;
78
+ }
79
+ const parentNewLineIndex = getNewLineIndex$1(parent);
80
+ const childNewLineIndex = getNewLineIndex$1(child);
81
+ if (childNewLineIndex === -1) {
82
+ return parent;
83
+ }
84
+ const parentFirstLine = parent.slice(0, parentNewLineIndex);
85
+ const childRest = child.slice(childNewLineIndex);
86
+ const childFirstLine = normalizeLine(child.slice(0, childNewLineIndex));
87
+ if (parentFirstLine.includes(childFirstLine)) {
88
+ return parentFirstLine + childRest;
89
+ }
90
+ return child;
91
+ };
92
+ class VError extends Error {
93
+ constructor(error, message) {
94
+ const combinedMessage = getCombinedMessage(error, message);
95
+ super(combinedMessage);
96
+ this.name = 'VError';
97
+ if (error instanceof Error) {
98
+ this.stack = mergeStacks(this.stack, error.stack);
99
+ }
100
+ if (error.codeFrame) {
101
+ // @ts-ignore
102
+ this.codeFrame = error.codeFrame;
103
+ }
104
+ if (error.code) {
105
+ // @ts-ignore
106
+ this.code = error.code;
107
+ }
108
+ }
109
+ }
110
+
17
111
  // @ts-ignore
18
112
  const getDisplayPath = path => {
19
113
  if (path === '') {
@@ -113,6 +207,1132 @@ process;
113
207
 
114
208
  const isElectron = Boolean(getElectronRunAsNode()) || 'electron' in process.versions;
115
209
 
210
+ const isMessagePort = value => {
211
+ return value && value instanceof MessagePort;
212
+ };
213
+ const isMessagePortMain = value => {
214
+ return value && value.constructor && value.constructor.name === 'MessagePortMain';
215
+ };
216
+ const isOffscreenCanvas = value => {
217
+ return typeof OffscreenCanvas !== 'undefined' && value instanceof OffscreenCanvas;
218
+ };
219
+ const isInstanceOf = (value, constructorName) => {
220
+ return value?.constructor?.name === constructorName;
221
+ };
222
+ const isSocket = value => {
223
+ return isInstanceOf(value, 'Socket');
224
+ };
225
+ const transferrables = [isMessagePort, isMessagePortMain, isOffscreenCanvas, isSocket];
226
+ const isTransferrable = value => {
227
+ for (const fn of transferrables) {
228
+ if (fn(value)) {
229
+ return true;
230
+ }
231
+ }
232
+ return false;
233
+ };
234
+ const walkValue = (value, transferrables, isTransferrable) => {
235
+ if (!value) {
236
+ return;
237
+ }
238
+ if (isTransferrable(value)) {
239
+ transferrables.push(value);
240
+ return;
241
+ }
242
+ if (Array.isArray(value)) {
243
+ for (const item of value) {
244
+ walkValue(item, transferrables, isTransferrable);
245
+ }
246
+ return;
247
+ }
248
+ if (typeof value === 'object') {
249
+ for (const property of Object.values(value)) {
250
+ walkValue(property, transferrables, isTransferrable);
251
+ }
252
+ return;
253
+ }
254
+ };
255
+ const getTransferrables = value => {
256
+ const transferrables = [];
257
+ walkValue(value, transferrables, isTransferrable);
258
+ return transferrables;
259
+ };
260
+ const removeValues = (value, toRemove) => {
261
+ if (!value) {
262
+ return value;
263
+ }
264
+ if (Array.isArray(value)) {
265
+ const newItems = [];
266
+ for (const item of value) {
267
+ if (!toRemove.includes(item)) {
268
+ newItems.push(removeValues(item, toRemove));
269
+ }
270
+ }
271
+ return newItems;
272
+ }
273
+ if (typeof value === 'object') {
274
+ const newObject = Object.create(null);
275
+ for (const [key, property] of Object.entries(value)) {
276
+ if (!toRemove.includes(property)) {
277
+ newObject[key] = removeValues(property, toRemove);
278
+ }
279
+ }
280
+ return newObject;
281
+ }
282
+ return value;
283
+ };
284
+
285
+ // workaround for electron not supporting transferrable objects
286
+ // as parameters. If the transferrable object is a parameter, in electron
287
+ // only an empty objected is received in the main process
288
+ const fixElectronParameters = value => {
289
+ const transfer = getTransferrables(value);
290
+ const newValue = removeValues(value, transfer);
291
+ return {
292
+ newValue,
293
+ transfer
294
+ };
295
+ };
296
+ const getActualDataElectron = event => {
297
+ const {
298
+ data,
299
+ ports
300
+ } = event;
301
+ if (ports.length === 0) {
302
+ return data;
303
+ }
304
+ return {
305
+ ...data,
306
+ params: [...ports, ...data.params]
307
+ };
308
+ };
309
+ const attachEvents = that => {
310
+ const handleMessage = (...args) => {
311
+ const data = that.getData(...args);
312
+ that.dispatchEvent(new MessageEvent('message', {
313
+ data
314
+ }));
315
+ };
316
+ that.onMessage(handleMessage);
317
+ const handleClose = event => {
318
+ that.dispatchEvent(new Event('close'));
319
+ };
320
+ that.onClose(handleClose);
321
+ };
322
+ class Ipc extends EventTarget {
323
+ constructor(rawIpc) {
324
+ super();
325
+ this._rawIpc = rawIpc;
326
+ attachEvents(this);
327
+ }
328
+ }
329
+ const E_INCOMPATIBLE_NATIVE_MODULE = 'E_INCOMPATIBLE_NATIVE_MODULE';
330
+ const E_MODULES_NOT_SUPPORTED_IN_ELECTRON = 'E_MODULES_NOT_SUPPORTED_IN_ELECTRON';
331
+ const ERR_MODULE_NOT_FOUND = 'ERR_MODULE_NOT_FOUND';
332
+ const NewLine$1 = '\n';
333
+ const joinLines$1 = lines => {
334
+ return lines.join(NewLine$1);
335
+ };
336
+ const RE_AT = /^\s+at/;
337
+ const RE_AT_PROMISE_INDEX = /^\s*at async Promise.all \(index \d+\)$/;
338
+ const isNormalStackLine = line => {
339
+ return RE_AT.test(line) && !RE_AT_PROMISE_INDEX.test(line);
340
+ };
341
+ const getDetails = lines => {
342
+ const index = lines.findIndex(isNormalStackLine);
343
+ if (index === -1) {
344
+ return {
345
+ actualMessage: joinLines$1(lines),
346
+ rest: []
347
+ };
348
+ }
349
+ let lastIndex = index - 1;
350
+ while (++lastIndex < lines.length) {
351
+ if (!isNormalStackLine(lines[lastIndex])) {
352
+ break;
353
+ }
354
+ }
355
+ return {
356
+ actualMessage: lines[index - 1],
357
+ rest: lines.slice(index, lastIndex)
358
+ };
359
+ };
360
+ const splitLines$1 = lines => {
361
+ return lines.split(NewLine$1);
362
+ };
363
+ const RE_MESSAGE_CODE_BLOCK_START = /^Error: The module '.*'$/;
364
+ const RE_MESSAGE_CODE_BLOCK_END = /^\s* at/;
365
+ const isMessageCodeBlockStartIndex = line => {
366
+ return RE_MESSAGE_CODE_BLOCK_START.test(line);
367
+ };
368
+ const isMessageCodeBlockEndIndex = line => {
369
+ return RE_MESSAGE_CODE_BLOCK_END.test(line);
370
+ };
371
+ const getMessageCodeBlock = stderr => {
372
+ const lines = splitLines$1(stderr);
373
+ const startIndex = lines.findIndex(isMessageCodeBlockStartIndex);
374
+ const endIndex = startIndex + lines.slice(startIndex).findIndex(isMessageCodeBlockEndIndex, startIndex);
375
+ const relevantLines = lines.slice(startIndex, endIndex);
376
+ const relevantMessage = relevantLines.join(' ').slice('Error: '.length);
377
+ return relevantMessage;
378
+ };
379
+ const isModuleNotFoundMessage = line => {
380
+ return line.includes('[ERR_MODULE_NOT_FOUND]');
381
+ };
382
+ const getModuleNotFoundError = stderr => {
383
+ const lines = splitLines$1(stderr);
384
+ const messageIndex = lines.findIndex(isModuleNotFoundMessage);
385
+ const message = lines[messageIndex];
386
+ return {
387
+ message,
388
+ code: ERR_MODULE_NOT_FOUND
389
+ };
390
+ };
391
+ const isModuleNotFoundError = stderr => {
392
+ if (!stderr) {
393
+ return false;
394
+ }
395
+ return stderr.includes('ERR_MODULE_NOT_FOUND');
396
+ };
397
+ const isModulesSyntaxError = stderr => {
398
+ if (!stderr) {
399
+ return false;
400
+ }
401
+ return stderr.includes('SyntaxError: Cannot use import statement outside a module');
402
+ };
403
+ const RE_NATIVE_MODULE_ERROR = /^innerError Error: Cannot find module '.*.node'/;
404
+ const RE_NATIVE_MODULE_ERROR_2 = /was compiled against a different Node.js version/;
405
+ const isUnhelpfulNativeModuleError = stderr => {
406
+ return RE_NATIVE_MODULE_ERROR.test(stderr) && RE_NATIVE_MODULE_ERROR_2.test(stderr);
407
+ };
408
+ const getNativeModuleErrorMessage = stderr => {
409
+ const message = getMessageCodeBlock(stderr);
410
+ return {
411
+ message: `Incompatible native node module: ${message}`,
412
+ code: E_INCOMPATIBLE_NATIVE_MODULE
413
+ };
414
+ };
415
+ const getModuleSyntaxError = () => {
416
+ return {
417
+ message: `ES Modules are not supported in electron`,
418
+ code: E_MODULES_NOT_SUPPORTED_IN_ELECTRON
419
+ };
420
+ };
421
+ const getHelpfulChildProcessError = (stdout, stderr) => {
422
+ if (isUnhelpfulNativeModuleError(stderr)) {
423
+ return getNativeModuleErrorMessage(stderr);
424
+ }
425
+ if (isModulesSyntaxError(stderr)) {
426
+ return getModuleSyntaxError();
427
+ }
428
+ if (isModuleNotFoundError(stderr)) {
429
+ return getModuleNotFoundError(stderr);
430
+ }
431
+ const lines = splitLines$1(stderr);
432
+ const {
433
+ actualMessage,
434
+ rest
435
+ } = getDetails(lines);
436
+ return {
437
+ message: actualMessage,
438
+ code: '',
439
+ stack: rest
440
+ };
441
+ };
442
+ class IpcError extends VError {
443
+ // @ts-ignore
444
+ constructor(betterMessage, stdout = '', stderr = '') {
445
+ if (stdout || stderr) {
446
+ // @ts-ignore
447
+ const {
448
+ message,
449
+ code,
450
+ stack
451
+ } = getHelpfulChildProcessError(stdout, stderr);
452
+ const cause = new Error(message);
453
+ // @ts-ignore
454
+ cause.code = code;
455
+ cause.stack = stack;
456
+ super(cause, betterMessage);
457
+ } else {
458
+ super(betterMessage);
459
+ }
460
+ // @ts-ignore
461
+ this.name = 'IpcError';
462
+ // @ts-ignore
463
+ this.stdout = stdout;
464
+ // @ts-ignore
465
+ this.stderr = stderr;
466
+ }
467
+ }
468
+ const listen$b = ({
469
+ messagePort
470
+ }) => {
471
+ if (!isMessagePortMain(messagePort)) {
472
+ throw new IpcError('port must be of type MessagePortMain');
473
+ }
474
+ return messagePort;
475
+ };
476
+ const signal$c = messagePort => {
477
+ messagePort.start();
478
+ };
479
+ class IpcChildWithElectronMessagePort extends Ipc {
480
+ getData = getActualDataElectron;
481
+ send(message) {
482
+ this._rawIpc.postMessage(message);
483
+ }
484
+ sendAndTransfer(message) {
485
+ const {
486
+ newValue,
487
+ transfer
488
+ } = fixElectronParameters(message);
489
+ this._rawIpc.postMessage(newValue, transfer);
490
+ }
491
+ dispose() {
492
+ this._rawIpc.close();
493
+ }
494
+ onMessage(callback) {
495
+ this._rawIpc.on('message', callback);
496
+ }
497
+ onClose(callback) {
498
+ this._rawIpc.on('close', callback);
499
+ }
500
+ }
501
+ const wrap$j = messagePort => {
502
+ return new IpcChildWithElectronMessagePort(messagePort);
503
+ };
504
+ const IpcChildWithElectronMessagePort$1 = {
505
+ __proto__: null,
506
+ listen: listen$b,
507
+ signal: signal$c,
508
+ wrap: wrap$j
509
+ };
510
+
511
+ // @ts-ignore
512
+ const getUtilityProcessPortData = event => {
513
+ const {
514
+ data,
515
+ ports
516
+ } = event;
517
+ if (ports.length === 0) {
518
+ return data;
519
+ }
520
+ return {
521
+ ...data,
522
+ params: [...ports, ...data.params]
523
+ };
524
+ };
525
+ const readyMessage = 'ready';
526
+ const listen$a = () => {
527
+ // @ts-ignore
528
+ const {
529
+ parentPort
530
+ } = process;
531
+ if (!parentPort) {
532
+ throw new Error('parent port must be defined');
533
+ }
534
+ return parentPort;
535
+ };
536
+ const signal$b = parentPort => {
537
+ parentPort.postMessage(readyMessage);
538
+ };
539
+ class IpcChildWithElectronUtilityProcess extends Ipc {
540
+ getData(event) {
541
+ return getUtilityProcessPortData(event);
542
+ }
543
+ send(message) {
544
+ this._rawIpc.postMessage(message);
545
+ }
546
+ sendAndTransfer(message) {
547
+ const {
548
+ newValue,
549
+ transfer
550
+ } = fixElectronParameters(message);
551
+ this._rawIpc.postMessage(newValue, transfer);
552
+ }
553
+ dispose() {
554
+ this._rawIpc.close();
555
+ }
556
+ onClose(callback) {
557
+ this._rawIpc.on('close', callback);
558
+ }
559
+ onMessage(callback) {
560
+ this._rawIpc.on('message', callback);
561
+ }
562
+ }
563
+ const wrap$i = parentPort => {
564
+ return new IpcChildWithElectronUtilityProcess(parentPort);
565
+ };
566
+ const IpcChildWithElectronUtilityProcess$1 = {
567
+ __proto__: null,
568
+ listen: listen$a,
569
+ signal: signal$b,
570
+ wrap: wrap$i
571
+ };
572
+ const getActualData = (message, handle) => {
573
+ if (handle) {
574
+ return {
575
+ ...message,
576
+ params: [handle, ...message.params]
577
+ };
578
+ }
579
+ return message;
580
+ };
581
+ const getTransferrablesNode = value => {
582
+ const transferrables = getTransferrables(value);
583
+ if (transferrables.length === 0) {
584
+ throw new Error(`no transferrables found`);
585
+ }
586
+ return transferrables[0];
587
+ };
588
+ const listen$5 = async () => {
589
+ if (!process.send) {
590
+ throw new Error('process.send must be defined');
591
+ }
592
+ return process;
593
+ };
594
+ const signal$7 = process => {
595
+ process.send(readyMessage);
596
+ };
597
+ class IpcChildWithNodeForkedProcess extends Ipc {
598
+ getData(message, handle) {
599
+ return getActualData(message, handle);
600
+ }
601
+ onClose(callback) {
602
+ this._rawIpc.on('close', callback);
603
+ }
604
+ send(message) {
605
+ this._rawIpc.send(message);
606
+ }
607
+ onMessage(callback) {
608
+ this._rawIpc.on('message', callback);
609
+ }
610
+ sendAndTransfer(message) {
611
+ const transfer = getTransferrablesNode(message);
612
+ this._rawIpc.send(message, transfer);
613
+ }
614
+ dispose() {
615
+ // ignore
616
+ }
617
+ }
618
+ const wrap$d = process => {
619
+ return new IpcChildWithNodeForkedProcess(process);
620
+ };
621
+ const IpcChildWithNodeForkedProcess$1 = {
622
+ __proto__: null,
623
+ listen: listen$5,
624
+ signal: signal$7,
625
+ wrap: wrap$d
626
+ };
627
+ const listen$3 = async () => {
628
+ const {
629
+ parentPort
630
+ } = await import('node:worker_threads');
631
+ if (!parentPort) {
632
+ throw new IpcError('parentPort is required');
633
+ }
634
+ return parentPort;
635
+ };
636
+ const signal$5 = parentPort => {
637
+ parentPort.postMessage(readyMessage);
638
+ };
639
+ class IpcChildWithNodeWorker extends Ipc {
640
+ getData(data) {
641
+ return data;
642
+ }
643
+ onClose(callback) {
644
+ this._rawIpc.on('close', callback);
645
+ }
646
+ send(message) {
647
+ this._rawIpc.postMessage(message);
648
+ }
649
+ onMessage(callback) {
650
+ this._rawIpc.on('message', callback);
651
+ }
652
+ sendAndTransfer(message) {
653
+ const transfer = getTransferrablesNode(message);
654
+ this._rawIpc.postMessage(message, transfer);
655
+ }
656
+ dispose() {
657
+ this._rawIpc.close();
658
+ }
659
+ }
660
+ const wrap$b = parentPort => {
661
+ return new IpcChildWithNodeWorker(parentPort);
662
+ };
663
+ const IpcChildWithNodeWorker$1 = {
664
+ __proto__: null,
665
+ listen: listen$3,
666
+ signal: signal$5,
667
+ wrap: wrap$b
668
+ };
669
+ const Open = 2;
670
+ const Close = 3;
671
+ const addListener = (emitter, type, callback) => {
672
+ if ('addEventListener' in emitter) {
673
+ emitter.addEventListener(type, callback);
674
+ } else {
675
+ emitter.on(type, callback);
676
+ }
677
+ };
678
+ const removeListener = (emitter, type, callback) => {
679
+ if ('removeEventListener' in emitter) {
680
+ emitter.removeEventListener(type, callback);
681
+ } else {
682
+ emitter.off(type, callback);
683
+ }
684
+ };
685
+ const getFirstEvent = (eventEmitter, eventMap) => {
686
+ const {
687
+ resolve,
688
+ promise
689
+ } = Promise.withResolvers();
690
+ const listenerMap = Object.create(null);
691
+ const cleanup = value => {
692
+ for (const event of Object.keys(eventMap)) {
693
+ removeListener(eventEmitter, event, listenerMap[event]);
694
+ }
695
+ resolve(value);
696
+ };
697
+ for (const [event, type] of Object.entries(eventMap)) {
698
+ const listener = event => {
699
+ cleanup({
700
+ type,
701
+ event
702
+ });
703
+ };
704
+ addListener(eventEmitter, event, listener);
705
+ listenerMap[event] = listener;
706
+ }
707
+ return promise;
708
+ };
709
+
710
+ // @ts-ignore
711
+ const getFirstWebSocketEvent = async webSocket => {
712
+ // @ts-ignore
713
+ const {
714
+ WebSocket
715
+ } = await import('ws');
716
+ switch (webSocket.readyState) {
717
+ case WebSocket.OPEN:
718
+ return {
719
+ type: Open,
720
+ event: undefined
721
+ };
722
+ case WebSocket.CLOSED:
723
+ return {
724
+ type: Close,
725
+ event: undefined
726
+ };
727
+ }
728
+ // @ts-ignore
729
+ const {
730
+ type,
731
+ event
732
+ } = await getFirstEvent(webSocket, {
733
+ open: Open,
734
+ close: Close
735
+ });
736
+ return {
737
+ type,
738
+ event
739
+ };
740
+ };
741
+
742
+ // @ts-ignore
743
+ const isWebSocketOpen = async webSocket => {
744
+ // @ts-ignore
745
+ const {
746
+ WebSocket
747
+ } = await import('ws');
748
+ return webSocket.readyState === WebSocket.OPEN;
749
+ };
750
+
751
+ // @ts-ignore
752
+ const serialize = message => {
753
+ return JSON.stringify(message);
754
+ };
755
+
756
+ // @ts-ignore
757
+ const deserialize = message => {
758
+ return JSON.parse(message.toString());
759
+ };
760
+
761
+ // @ts-ignore
762
+ const handleUpgrade$1 = async (...args) => {
763
+ const module = await Promise.resolve().then(function () { return index; });
764
+ // @ts-ignore
765
+ return module.handleUpgrade(...args);
766
+ };
767
+
768
+ // @ts-ignore
769
+ const listen$1$1 = async ({
770
+ request,
771
+ handle
772
+ }) => {
773
+ if (!request) {
774
+ throw new IpcError('request must be defined');
775
+ }
776
+ if (!handle) {
777
+ throw new IpcError('handle must be defined');
778
+ }
779
+ const webSocket = await handleUpgrade$1(request, handle);
780
+ webSocket.pause();
781
+ if (!(await isWebSocketOpen(webSocket))) {
782
+ await getFirstWebSocketEvent(webSocket);
783
+ }
784
+ return webSocket;
785
+ };
786
+ const signal$4 = webSocket => {
787
+ webSocket.resume();
788
+ };
789
+
790
+ // @ts-ignore
791
+ const wrap$9 = webSocket => {
792
+ return {
793
+ webSocket,
794
+ /**
795
+ * @type {any}
796
+ */
797
+ wrappedListener: undefined,
798
+ // @ts-ignore
799
+ on(event, listener) {
800
+ switch (event) {
801
+ case 'message':
802
+ // @ts-ignore
803
+ const wrappedListener = message => {
804
+ const data = deserialize(message);
805
+ const event = {
806
+ data,
807
+ target: this
808
+ };
809
+ listener(event);
810
+ };
811
+ webSocket.on('message', wrappedListener);
812
+ break;
813
+ case 'close':
814
+ webSocket.on('close', listener);
815
+ break;
816
+ default:
817
+ throw new Error('unknown event listener type');
818
+ }
819
+ },
820
+ // @ts-ignore
821
+ off(event, listener) {
822
+ this.webSocket.off(event, listener);
823
+ },
824
+ // @ts-ignore
825
+ send(message) {
826
+ const stringifiedMessage = serialize(message);
827
+ this.webSocket.send(stringifiedMessage);
828
+ },
829
+ dispose() {
830
+ this.webSocket.close();
831
+ },
832
+ start() {
833
+ throw new Error('start method is deprecated');
834
+ }
835
+ };
836
+ };
837
+ const IpcChildWithWebSocket = {
838
+ __proto__: null,
839
+ listen: listen$1$1,
840
+ signal: signal$4,
841
+ wrap: wrap$9
842
+ };
843
+
844
+ const Two = '2.0';
845
+ const create$4$1 = (method, params) => {
846
+ return {
847
+ jsonrpc: Two,
848
+ method,
849
+ params
850
+ };
851
+ };
852
+ const callbacks = Object.create(null);
853
+ const set = (id, fn) => {
854
+ callbacks[id] = fn;
855
+ };
856
+ const get = id => {
857
+ return callbacks[id];
858
+ };
859
+ const remove$1 = id => {
860
+ delete callbacks[id];
861
+ };
862
+ let id = 0;
863
+ const create$3 = () => {
864
+ return ++id;
865
+ };
866
+ const registerPromise = () => {
867
+ const id = create$3();
868
+ const {
869
+ resolve,
870
+ promise
871
+ } = Promise.withResolvers();
872
+ set(id, resolve);
873
+ return {
874
+ id,
875
+ promise
876
+ };
877
+ };
878
+ const create$2 = (method, params) => {
879
+ const {
880
+ id,
881
+ promise
882
+ } = registerPromise();
883
+ const message = {
884
+ jsonrpc: Two,
885
+ method,
886
+ params,
887
+ id
888
+ };
889
+ return {
890
+ message,
891
+ promise
892
+ };
893
+ };
894
+ class JsonRpcError extends Error {
895
+ constructor(message) {
896
+ super(message);
897
+ this.name = 'JsonRpcError';
898
+ }
899
+ }
900
+ const NewLine = '\n';
901
+ const DomException = 'DOMException';
902
+ const ReferenceError$1 = 'ReferenceError';
903
+ const SyntaxError$1 = 'SyntaxError';
904
+ const TypeError$1 = 'TypeError';
905
+ const getErrorConstructor = (message, type) => {
906
+ if (type) {
907
+ switch (type) {
908
+ case DomException:
909
+ return DOMException;
910
+ case TypeError$1:
911
+ return TypeError;
912
+ case SyntaxError$1:
913
+ return SyntaxError;
914
+ case ReferenceError$1:
915
+ return ReferenceError;
916
+ default:
917
+ return Error;
918
+ }
919
+ }
920
+ if (message.startsWith('TypeError: ')) {
921
+ return TypeError;
922
+ }
923
+ if (message.startsWith('SyntaxError: ')) {
924
+ return SyntaxError;
925
+ }
926
+ if (message.startsWith('ReferenceError: ')) {
927
+ return ReferenceError;
928
+ }
929
+ return Error;
930
+ };
931
+ const constructError = (message, type, name) => {
932
+ const ErrorConstructor = getErrorConstructor(message, type);
933
+ if (ErrorConstructor === DOMException && name) {
934
+ return new ErrorConstructor(message, name);
935
+ }
936
+ if (ErrorConstructor === Error) {
937
+ const error = new Error(message);
938
+ if (name && name !== 'VError') {
939
+ error.name = name;
940
+ }
941
+ return error;
942
+ }
943
+ return new ErrorConstructor(message);
944
+ };
945
+ const getNewLineIndex = (string, startIndex = undefined) => {
946
+ return string.indexOf(NewLine, startIndex);
947
+ };
948
+ const getParentStack = error => {
949
+ let parentStack = error.stack || error.data || error.message || '';
950
+ if (parentStack.startsWith(' at')) {
951
+ parentStack = error.message + NewLine + parentStack;
952
+ }
953
+ return parentStack;
954
+ };
955
+ const joinLines = lines => {
956
+ return lines.join(NewLine);
957
+ };
958
+ const MethodNotFound = -32601;
959
+ const Custom = -32001;
960
+ const splitLines = lines => {
961
+ return lines.split(NewLine);
962
+ };
963
+ const restoreJsonRpcError = error => {
964
+ if (error && error instanceof Error) {
965
+ return error;
966
+ }
967
+ const currentStack = joinLines(splitLines(new Error().stack || '').slice(1));
968
+ if (error && error.code && error.code === MethodNotFound) {
969
+ const restoredError = new JsonRpcError(error.message);
970
+ const parentStack = getParentStack(error);
971
+ restoredError.stack = parentStack + NewLine + currentStack;
972
+ return restoredError;
973
+ }
974
+ if (error && error.message) {
975
+ const restoredError = constructError(error.message, error.type, error.name);
976
+ if (error.data) {
977
+ if (error.data.stack && error.data.type && error.message) {
978
+ restoredError.stack = error.data.type + ': ' + error.message + NewLine + error.data.stack + NewLine + currentStack;
979
+ } else if (error.data.stack) {
980
+ restoredError.stack = error.data.stack;
981
+ }
982
+ if (error.data.codeFrame) {
983
+ // @ts-ignore
984
+ restoredError.codeFrame = error.data.codeFrame;
985
+ }
986
+ if (error.data.code) {
987
+ // @ts-ignore
988
+ restoredError.code = error.data.code;
989
+ }
990
+ if (error.data.type) {
991
+ // @ts-ignore
992
+ restoredError.name = error.data.type;
993
+ }
994
+ } else {
995
+ if (error.stack) {
996
+ const lowerStack = restoredError.stack || '';
997
+ // @ts-ignore
998
+ const indexNewLine = getNewLineIndex(lowerStack);
999
+ const parentStack = getParentStack(error);
1000
+ // @ts-ignore
1001
+ restoredError.stack = parentStack + lowerStack.slice(indexNewLine);
1002
+ }
1003
+ if (error.codeFrame) {
1004
+ // @ts-ignore
1005
+ restoredError.codeFrame = error.codeFrame;
1006
+ }
1007
+ }
1008
+ return restoredError;
1009
+ }
1010
+ if (typeof error === 'string') {
1011
+ return new Error(`JsonRpc Error: ${error}`);
1012
+ }
1013
+ return new Error(`JsonRpc Error: ${error}`);
1014
+ };
1015
+ const unwrapJsonRpcResult = responseMessage => {
1016
+ if ('error' in responseMessage) {
1017
+ const restoredError = restoreJsonRpcError(responseMessage.error);
1018
+ throw restoredError;
1019
+ }
1020
+ if ('result' in responseMessage) {
1021
+ return responseMessage.result;
1022
+ }
1023
+ throw new JsonRpcError('unexpected response message');
1024
+ };
1025
+ const warn = (...args) => {
1026
+ console.warn(...args);
1027
+ };
1028
+ const resolve = (id, response) => {
1029
+ const fn = get(id);
1030
+ if (!fn) {
1031
+ console.log(response);
1032
+ warn(`callback ${id} may already be disposed`);
1033
+ return;
1034
+ }
1035
+ fn(response);
1036
+ remove$1(id);
1037
+ };
1038
+ const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
1039
+ const getErrorType = prettyError => {
1040
+ if (prettyError && prettyError.type) {
1041
+ return prettyError.type;
1042
+ }
1043
+ if (prettyError && prettyError.constructor && prettyError.constructor.name) {
1044
+ return prettyError.constructor.name;
1045
+ }
1046
+ return undefined;
1047
+ };
1048
+ const getErrorProperty = (error, prettyError) => {
1049
+ if (error && error.code === E_COMMAND_NOT_FOUND) {
1050
+ return {
1051
+ code: MethodNotFound,
1052
+ message: error.message,
1053
+ data: error.stack
1054
+ };
1055
+ }
1056
+ return {
1057
+ code: Custom,
1058
+ message: prettyError.message,
1059
+ data: {
1060
+ stack: prettyError.stack,
1061
+ codeFrame: prettyError.codeFrame,
1062
+ type: getErrorType(prettyError),
1063
+ code: prettyError.code,
1064
+ name: prettyError.name
1065
+ }
1066
+ };
1067
+ };
1068
+ const create$1 = (message, error) => {
1069
+ return {
1070
+ jsonrpc: Two,
1071
+ id: message.id,
1072
+ error
1073
+ };
1074
+ };
1075
+ const getErrorResponse = (message, error, preparePrettyError, logError) => {
1076
+ const prettyError = preparePrettyError(error);
1077
+ logError(error, prettyError);
1078
+ const errorProperty = getErrorProperty(error, prettyError);
1079
+ return create$1(message, errorProperty);
1080
+ };
1081
+ const create = (message, result) => {
1082
+ return {
1083
+ jsonrpc: Two,
1084
+ id: message.id,
1085
+ result: result ?? null
1086
+ };
1087
+ };
1088
+ const getSuccessResponse = (message, result) => {
1089
+ const resultProperty = result ?? null;
1090
+ return create(message, resultProperty);
1091
+ };
1092
+ const getResponse = async (message, ipc, execute, preparePrettyError, logError, requiresSocket) => {
1093
+ try {
1094
+ const result = requiresSocket(message.method) ? await execute(message.method, ipc, ...message.params) : await execute(message.method, ...message.params);
1095
+ return getSuccessResponse(message, result);
1096
+ } catch (error) {
1097
+ return getErrorResponse(message, error, preparePrettyError, logError);
1098
+ }
1099
+ };
1100
+ const defaultPreparePrettyError = error => {
1101
+ return error;
1102
+ };
1103
+ const defaultLogError = () => {
1104
+ // ignore
1105
+ };
1106
+ const defaultRequiresSocket = () => {
1107
+ return false;
1108
+ };
1109
+ const defaultResolve = resolve;
1110
+
1111
+ // TODO maybe remove this in v6 or v7, only accept options object to simplify the code
1112
+ const normalizeParams = args => {
1113
+ if (args.length === 1) {
1114
+ const options = args[0];
1115
+ return {
1116
+ ipc: options.ipc,
1117
+ message: options.message,
1118
+ execute: options.execute,
1119
+ resolve: options.resolve || defaultResolve,
1120
+ preparePrettyError: options.preparePrettyError || defaultPreparePrettyError,
1121
+ logError: options.logError || defaultLogError,
1122
+ requiresSocket: options.requiresSocket || defaultRequiresSocket
1123
+ };
1124
+ }
1125
+ return {
1126
+ ipc: args[0],
1127
+ message: args[1],
1128
+ execute: args[2],
1129
+ resolve: args[3],
1130
+ preparePrettyError: args[4],
1131
+ logError: args[5],
1132
+ requiresSocket: args[6]
1133
+ };
1134
+ };
1135
+ const handleJsonRpcMessage = async (...args) => {
1136
+ const options = normalizeParams(args);
1137
+ const {
1138
+ message,
1139
+ ipc,
1140
+ execute,
1141
+ resolve,
1142
+ preparePrettyError,
1143
+ logError,
1144
+ requiresSocket
1145
+ } = options;
1146
+ if ('id' in message) {
1147
+ if ('method' in message) {
1148
+ const response = await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1149
+ try {
1150
+ ipc.send(response);
1151
+ } catch (error) {
1152
+ const errorResponse = getErrorResponse(message, error, preparePrettyError, logError);
1153
+ ipc.send(errorResponse);
1154
+ }
1155
+ return;
1156
+ }
1157
+ resolve(message.id, message);
1158
+ return;
1159
+ }
1160
+ if ('method' in message) {
1161
+ await getResponse(message, ipc, execute, preparePrettyError, logError, requiresSocket);
1162
+ return;
1163
+ }
1164
+ throw new JsonRpcError('unexpected message');
1165
+ };
1166
+ const invokeHelper = async (ipc, method, params, useSendAndTransfer) => {
1167
+ const {
1168
+ message,
1169
+ promise
1170
+ } = create$2(method, params);
1171
+ if (useSendAndTransfer && ipc.sendAndTransfer) {
1172
+ ipc.sendAndTransfer(message);
1173
+ } else {
1174
+ ipc.send(message);
1175
+ }
1176
+ const responseMessage = await promise;
1177
+ return unwrapJsonRpcResult(responseMessage);
1178
+ };
1179
+ const send = (transport, method, ...params) => {
1180
+ const message = create$4$1(method, params);
1181
+ transport.send(message);
1182
+ };
1183
+ const invoke$1 = (ipc, method, ...params) => {
1184
+ return invokeHelper(ipc, method, params, false);
1185
+ };
1186
+ const invokeAndTransfer = (ipc, method, ...params) => {
1187
+ return invokeHelper(ipc, method, params, true);
1188
+ };
1189
+
1190
+ const commands = Object.create(null);
1191
+ const register = commandMap => {
1192
+ Object.assign(commands, commandMap);
1193
+ };
1194
+ const getCommand = key => {
1195
+ return commands[key];
1196
+ };
1197
+ const execute = (command, ...args) => {
1198
+ const fn = getCommand(command);
1199
+ if (!fn) {
1200
+ throw new Error(`command not found ${command}`);
1201
+ }
1202
+ return fn(...args);
1203
+ };
1204
+
1205
+ const createRpc = ipc => {
1206
+ const rpc = {
1207
+ // @ts-ignore
1208
+ ipc,
1209
+ /**
1210
+ * @deprecated
1211
+ */
1212
+ send(method, ...params) {
1213
+ send(ipc, method, ...params);
1214
+ },
1215
+ invoke(method, ...params) {
1216
+ return invoke$1(ipc, method, ...params);
1217
+ },
1218
+ invokeAndTransfer(method, ...params) {
1219
+ return invokeAndTransfer(ipc, method, ...params);
1220
+ },
1221
+ async dispose() {
1222
+ await ipc?.dispose();
1223
+ }
1224
+ };
1225
+ return rpc;
1226
+ };
1227
+ const requiresSocket = () => {
1228
+ return false;
1229
+ };
1230
+ const preparePrettyError = error => {
1231
+ return error;
1232
+ };
1233
+ const logError = () => {
1234
+ // handled by renderer worker
1235
+ };
1236
+ const handleMessage = event => {
1237
+ const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
1238
+ const actualExecute = event?.target?.execute || execute;
1239
+ return handleJsonRpcMessage(event.target, event.data, actualExecute, resolve, preparePrettyError, logError, actualRequiresSocket);
1240
+ };
1241
+ const handleIpc = ipc => {
1242
+ if ('addEventListener' in ipc) {
1243
+ ipc.addEventListener('message', handleMessage);
1244
+ } else if ('on' in ipc) {
1245
+ // deprecated
1246
+ ipc.on('message', handleMessage);
1247
+ }
1248
+ };
1249
+ const listen$2 = async (module, options) => {
1250
+ const rawIpc = await module.listen(options);
1251
+ if (module.signal) {
1252
+ module.signal(rawIpc);
1253
+ }
1254
+ const ipc = module.wrap(rawIpc);
1255
+ return ipc;
1256
+ };
1257
+ const create$c = async ({
1258
+ commandMap,
1259
+ messagePort
1260
+ }) => {
1261
+ // TODO create a commandMap per rpc instance
1262
+ register(commandMap);
1263
+ const ipc = await listen$2(IpcChildWithElectronMessagePort$1, {
1264
+ messagePort
1265
+ });
1266
+ handleIpc(ipc);
1267
+ const rpc = createRpc(ipc);
1268
+ return rpc;
1269
+ };
1270
+ const ElectronMessagePortRpcClient = {
1271
+ __proto__: null,
1272
+ create: create$c
1273
+ };
1274
+ const create$b = async ({
1275
+ commandMap
1276
+ }) => {
1277
+ // TODO create a commandMap per rpc instance
1278
+ register(commandMap);
1279
+ const ipc = await listen$2(IpcChildWithElectronUtilityProcess$1);
1280
+ handleIpc(ipc);
1281
+ const rpc = createRpc(ipc);
1282
+ return rpc;
1283
+ };
1284
+ const ElectronUtilityProcessRpcClient = {
1285
+ __proto__: null,
1286
+ create: create$b
1287
+ };
1288
+ const create$7 = async ({
1289
+ commandMap
1290
+ }) => {
1291
+ // TODO create a commandMap per rpc instance
1292
+ register(commandMap);
1293
+ const ipc = await listen$2(IpcChildWithNodeForkedProcess$1);
1294
+ handleIpc(ipc);
1295
+ const rpc = createRpc(ipc);
1296
+ return rpc;
1297
+ };
1298
+ const NodeForkedProcessRpcClient = {
1299
+ __proto__: null,
1300
+ create: create$7
1301
+ };
1302
+ const create$5 = async ({
1303
+ commandMap,
1304
+ request,
1305
+ handle
1306
+ }) => {
1307
+ // TODO create a commandMap per rpc instance
1308
+ register(commandMap);
1309
+ const ipc = await listen$2(IpcChildWithWebSocket, {
1310
+ request,
1311
+ handle
1312
+ });
1313
+ handleIpc(ipc);
1314
+ const rpc = createRpc(ipc);
1315
+ return rpc;
1316
+ };
1317
+ const NodeWebSocketRpcClient = {
1318
+ __proto__: null,
1319
+ create: create$5
1320
+ };
1321
+ const create$4 = async ({
1322
+ commandMap
1323
+ }) => {
1324
+ // TODO create a commandMap per rpc instance
1325
+ register(commandMap);
1326
+ const ipc = await listen$2(IpcChildWithNodeWorker$1);
1327
+ handleIpc(ipc);
1328
+ const rpc = createRpc(ipc);
1329
+ return rpc;
1330
+ };
1331
+ const NodeWorkerRpcClient = {
1332
+ __proto__: null,
1333
+ create: create$4
1334
+ };
1335
+
116
1336
  const NodeWorker = 1;
117
1337
  const NodeForkedProcess = 2;
118
1338
  const ElectronUtilityProcess = 3;
@@ -416,9 +1636,20 @@ const getFolderSize = async uri => {
416
1636
  return total;
417
1637
  };
418
1638
 
1639
+ const handleWebSocket = async (handle, request) => {
1640
+ object(handle);
1641
+ object(request);
1642
+ await listen$1({
1643
+ method: WebSocket,
1644
+ request,
1645
+ handle
1646
+ });
1647
+ };
1648
+
419
1649
  const commandMap = {
420
1650
  'FileSystem.chmod': chmod,
421
1651
  'FileSystem.copy': copy,
1652
+ 'FileSystem.getFolderSize': getFolderSize,
422
1653
  'FileSystem.getPathSeparator': getPathSeparator,
423
1654
  'FileSystem.mkdir': mkdir,
424
1655
  'FileSystem.readDirWithFileTypes': readDirWithFileTypes,
@@ -428,7 +1659,7 @@ const commandMap = {
428
1659
  'FileSystem.rename': rename,
429
1660
  'FileSystem.stat': stat,
430
1661
  'FileSystem.writeFile': writeFile,
431
- 'FileSystem.getFolderSize': getFolderSize
1662
+ 'HandleWebSocket.handleWebSocket': handleWebSocket
432
1663
  };
433
1664
 
434
1665
  const listen = async argv => {
@@ -443,3 +1674,36 @@ const main = async () => {
443
1674
  };
444
1675
 
445
1676
  main();
1677
+
1678
+ const createWebSocketServer = async () => {
1679
+ const _ws = await import('ws');
1680
+ // workaround for jest or node bug
1681
+ const WebSocketServer = _ws.WebSocketServer ? _ws.WebSocketServer :
1682
+ // @ts-ignore
1683
+ _ws.default.WebSocketServer;
1684
+ const webSocketServer = new WebSocketServer({
1685
+ noServer: true
1686
+
1687
+ // TODO not sure if ws compress is working at all
1688
+ // perMessageDeflate: true
1689
+ });
1690
+ return webSocketServer;
1691
+ };
1692
+ const doSocketUpgrade = (webSocketServer, request, socket) => {
1693
+ const {
1694
+ promise,
1695
+ resolve
1696
+ } = Promise.withResolvers();
1697
+ webSocketServer.handleUpgrade(request, socket, Buffer.alloc(0), resolve);
1698
+ return promise;
1699
+ };
1700
+ const handleUpgrade = async (request, socket) => {
1701
+ const webSocketServer = await createWebSocketServer();
1702
+ const webSocket = await doSocketUpgrade(webSocketServer, request, socket);
1703
+ return webSocket;
1704
+ };
1705
+
1706
+ const index = {
1707
+ __proto__: null,
1708
+ handleUpgrade
1709
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/file-system-process",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "File System Process",
5
5
  "keywords": [
6
6
  "Lvce Editor",
@@ -18,12 +18,8 @@
18
18
  "file-system-process": "bin/fileSystemProcess.js"
19
19
  },
20
20
  "dependencies": {
21
- "@lvce-editor/assert": "^1.3.0",
22
- "@lvce-editor/json-rpc": "^5.4.0",
23
- "@lvce-editor/rpc": "^1.27.0",
24
- "@lvce-editor/verror": "^1.6.0",
25
21
  "execa": "^9.5.2",
26
- "open": "^10.1.1",
22
+ "open": "^10.1.2",
27
23
  "tail": "^2.2.6",
28
24
  "tmp-promise": "^3.0.3",
29
25
  "trash": "^9.0.0"