@lvce-editor/extension-management-worker 1.4.0 → 1.6.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.
@@ -368,6 +368,9 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
368
368
  listen: listen$6,
369
369
  wrap: wrap$e
370
370
  };
371
+ const Error$3 = 1;
372
+ const Open = 2;
373
+ const Close = 3;
371
374
  const addListener = (emitter, type, callback) => {
372
375
  if ('addEventListener' in emitter) {
373
376
  emitter.addEventListener(type, callback);
@@ -462,9 +465,69 @@ const IpcParentWithMessagePort$1 = {
462
465
  signal: signal$1,
463
466
  wrap: wrap$5
464
467
  };
468
+ const stringifyCompact = value => {
469
+ return JSON.stringify(value);
470
+ };
471
+ const parse = content => {
472
+ if (content === 'undefined') {
473
+ return null;
474
+ }
475
+ try {
476
+ return JSON.parse(content);
477
+ } catch (error) {
478
+ throw new VError(error, 'failed to parse json');
479
+ }
480
+ };
481
+ const waitForWebSocketToBeOpen = webSocket => {
482
+ return getFirstEvent(webSocket, {
483
+ open: Open,
484
+ close: Close,
485
+ error: Error$3
486
+ });
487
+ };
488
+ const create$7 = async ({
489
+ webSocket
490
+ }) => {
491
+ const firstWebSocketEvent = await waitForWebSocketToBeOpen(webSocket);
492
+ if (firstWebSocketEvent.type === Error$3) {
493
+ throw new IpcError(`WebSocket connection error`);
494
+ }
495
+ if (firstWebSocketEvent.type === Close) {
496
+ throw new IpcError('Websocket connection was immediately closed');
497
+ }
498
+ return webSocket;
499
+ };
500
+ class IpcParentWithWebSocket extends Ipc {
501
+ getData(event) {
502
+ return parse(event.data);
503
+ }
504
+ send(message) {
505
+ this._rawIpc.send(stringifyCompact(message));
506
+ }
507
+ sendAndTransfer(message) {
508
+ throw new Error('sendAndTransfer not supported');
509
+ }
510
+ dispose() {
511
+ this._rawIpc.close();
512
+ }
513
+ onClose(callback) {
514
+ this._rawIpc.addEventListener('close', callback);
515
+ }
516
+ onMessage(callback) {
517
+ this._rawIpc.addEventListener('message', callback);
518
+ }
519
+ }
520
+ const wrap = webSocket => {
521
+ return new IpcParentWithWebSocket(webSocket);
522
+ };
523
+ const IpcParentWithWebSocket$1 = {
524
+ __proto__: null,
525
+ create: create$7,
526
+ wrap
527
+ };
465
528
 
466
529
  const Two = '2.0';
467
- const create$4 = (method, params) => {
530
+ const create$4$1 = (method, params) => {
468
531
  return {
469
532
  jsonrpc: Two,
470
533
  method,
@@ -472,7 +535,7 @@ const create$4 = (method, params) => {
472
535
  };
473
536
  };
474
537
  const callbacks = Object.create(null);
475
- const set$3 = (id, fn) => {
538
+ const set$5 = (id, fn) => {
476
539
  callbacks[id] = fn;
477
540
  };
478
541
  const get$2 = id => {
@@ -482,22 +545,22 @@ const remove = id => {
482
545
  delete callbacks[id];
483
546
  };
484
547
  let id = 0;
485
- const create$3 = () => {
548
+ const create$3$1 = () => {
486
549
  return ++id;
487
550
  };
488
551
  const registerPromise = () => {
489
- const id = create$3();
552
+ const id = create$3$1();
490
553
  const {
491
554
  resolve,
492
555
  promise
493
556
  } = Promise.withResolvers();
494
- set$3(id, resolve);
557
+ set$5(id, resolve);
495
558
  return {
496
559
  id,
497
560
  promise
498
561
  };
499
562
  };
500
- const create$2 = (method, params) => {
563
+ const create$2$1 = (method, params) => {
501
564
  const {
502
565
  id,
503
566
  promise
@@ -706,7 +769,7 @@ const getErrorProperty = (error, prettyError) => {
706
769
  }
707
770
  };
708
771
  };
709
- const create$1$1 = (id, error) => {
772
+ const create$1$2 = (id, error) => {
710
773
  return {
711
774
  jsonrpc: Two,
712
775
  id,
@@ -717,7 +780,7 @@ const getErrorResponse = (id, error, preparePrettyError, logError) => {
717
780
  const prettyError = preparePrettyError(error);
718
781
  logError(error, prettyError);
719
782
  const errorProperty = getErrorProperty(error, prettyError);
720
- return create$1$1(id, errorProperty);
783
+ return create$1$2(id, errorProperty);
721
784
  };
722
785
  const create$6 = (message, result) => {
723
786
  return {
@@ -823,7 +886,7 @@ const invokeHelper = async (ipc, method, params, useSendAndTransfer) => {
823
886
  const {
824
887
  message,
825
888
  promise
826
- } = create$2(method, params);
889
+ } = create$2$1(method, params);
827
890
  if (useSendAndTransfer && ipc.sendAndTransfer) {
828
891
  ipc.sendAndTransfer(message);
829
892
  } else {
@@ -833,13 +896,13 @@ const invokeHelper = async (ipc, method, params, useSendAndTransfer) => {
833
896
  return unwrapJsonRpcResult(responseMessage);
834
897
  };
835
898
  const send = (transport, method, ...params) => {
836
- const message = create$4(method, params);
899
+ const message = create$4$1(method, params);
837
900
  transport.send(message);
838
901
  };
839
- const invoke$2 = (ipc, method, ...params) => {
902
+ const invoke$3 = (ipc, method, ...params) => {
840
903
  return invokeHelper(ipc, method, params, false);
841
904
  };
842
- const invokeAndTransfer = (ipc, method, ...params) => {
905
+ const invokeAndTransfer$1 = (ipc, method, ...params) => {
843
906
  return invokeHelper(ipc, method, params, true);
844
907
  };
845
908
 
@@ -875,10 +938,10 @@ const createRpc = ipc => {
875
938
  send(ipc, method, ...params);
876
939
  },
877
940
  invoke(method, ...params) {
878
- return invoke$2(ipc, method, ...params);
941
+ return invoke$3(ipc, method, ...params);
879
942
  },
880
943
  invokeAndTransfer(method, ...params) {
881
- return invokeAndTransfer(ipc, method, ...params);
944
+ return invokeAndTransfer$1(ipc, method, ...params);
882
945
  },
883
946
  async dispose() {
884
947
  await ipc?.dispose();
@@ -936,7 +999,73 @@ const PlainMessagePortRpc = {
936
999
  __proto__: null,
937
1000
  create: create$5
938
1001
  };
939
- const create$1 = async ({
1002
+ const create$3 = async ({
1003
+ commandMap,
1004
+ send
1005
+ }) => {
1006
+ const {
1007
+ port1,
1008
+ port2
1009
+ } = new MessageChannel();
1010
+ await send(port1);
1011
+ return create$5({
1012
+ commandMap,
1013
+ messagePort: port2
1014
+ });
1015
+ };
1016
+ const TransferMessagePortRpcParent = {
1017
+ __proto__: null,
1018
+ create: create$3
1019
+ };
1020
+ const create$2 = async ({
1021
+ commandMap,
1022
+ webSocket
1023
+ }) => {
1024
+ // TODO create a commandMap per rpc instance
1025
+ register(commandMap);
1026
+ const rawIpc = await IpcParentWithWebSocket$1.create({
1027
+ webSocket
1028
+ });
1029
+ const ipc = IpcParentWithWebSocket$1.wrap(rawIpc);
1030
+ handleIpc(ipc);
1031
+ const rpc = createRpc(ipc);
1032
+ return rpc;
1033
+ };
1034
+ const Https = 'https:';
1035
+ const Ws = 'ws:';
1036
+ const Wss = 'wss:';
1037
+ const getWebSocketProtocol = locationProtocol => {
1038
+ return locationProtocol === Https ? Wss : Ws;
1039
+ };
1040
+ const getWebSocketUrl = (type, host, locationProtocol) => {
1041
+ const wsProtocol = getWebSocketProtocol(locationProtocol);
1042
+ return `${wsProtocol}//${host}/websocket/${type}`;
1043
+ };
1044
+ const getHost = () => {
1045
+ return location.host;
1046
+ };
1047
+ const getProtocol = () => {
1048
+ return location.protocol;
1049
+ };
1050
+ const create$1$1 = async ({
1051
+ commandMap,
1052
+ type
1053
+ }) => {
1054
+ const host = getHost();
1055
+ const protocol = getProtocol();
1056
+ const wsUrl = getWebSocketUrl(type, host, protocol);
1057
+ const webSocket = new WebSocket(wsUrl);
1058
+ const rpc = await create$2({
1059
+ webSocket,
1060
+ commandMap
1061
+ });
1062
+ return rpc;
1063
+ };
1064
+ const WebSocketRpcParent2 = {
1065
+ __proto__: null,
1066
+ create: create$1$1
1067
+ };
1068
+ const create$4 = async ({
940
1069
  commandMap
941
1070
  }) => {
942
1071
  // TODO create a commandMap per rpc instance
@@ -948,21 +1077,26 @@ const create$1 = async ({
948
1077
  };
949
1078
  const WebWorkerRpcClient = {
950
1079
  __proto__: null,
951
- create: create$1
1080
+ create: create$4
952
1081
  };
953
1082
 
1083
+ const Web = 1;
1084
+ const Electron = 2;
1085
+ const Remote = 3;
1086
+
1087
+ const FileSystemWorker = 209;
954
1088
  const RendererWorker = 1;
955
1089
  const SharedProcess = 1;
956
1090
 
957
1091
  const rpcs = Object.create(null);
958
- const set$2 = (id, rpc) => {
1092
+ const set$4 = (id, rpc) => {
959
1093
  rpcs[id] = rpc;
960
1094
  };
961
1095
  const get$1 = id => {
962
1096
  return rpcs[id];
963
1097
  };
964
1098
 
965
- const create = rpcId => {
1099
+ const create$1 = rpcId => {
966
1100
  return {
967
1101
  async dispose() {
968
1102
  const rpc = get$1(rpcId);
@@ -981,41 +1115,202 @@ const create = rpcId => {
981
1115
  return rpc.invokeAndTransfer(method, ...params);
982
1116
  },
983
1117
  set(rpc) {
984
- set$2(rpcId, rpc);
1118
+ set$4(rpcId, rpc);
985
1119
  }
986
1120
  };
987
1121
  };
988
1122
 
1123
+ const {
1124
+ invoke: invoke$2,
1125
+ set: set$3
1126
+ } = create$1(FileSystemWorker);
1127
+ const readFile = async uri => {
1128
+ return invoke$2('FileSystem.readFile', uri);
1129
+ };
1130
+ const writeFile = async (uri, content) => {
1131
+ return invoke$2('FileSystem.writeFile', uri, content);
1132
+ };
1133
+ const exists = async uri => {
1134
+ // @ts-ignore
1135
+ return invoke$2('FileSystem.exists', uri);
1136
+ };
1137
+
989
1138
  const {
990
1139
  invoke: invoke$1,
991
- set: set$1
992
- } = create(RendererWorker);
1140
+ invokeAndTransfer,
1141
+ set: set$2
1142
+ } = create$1(RendererWorker);
1143
+ const sendMessagePortToFileSystemWorker = async (port, rpcId) => {
1144
+ const command = 'FileSystem.handleMessagePort';
1145
+ // @ts-ignore
1146
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToFileSystemWorker', port, command, rpcId);
1147
+ };
1148
+ const sendMessagePortToSharedProcess = async port => {
1149
+ const command = 'HandleElectronMessagePort.handleElectronMessagePort';
1150
+ // @ts-ignore
1151
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToSharedProcess', port, command, 0);
1152
+ };
993
1153
  const getExtension$1 = async id => {
994
1154
  // @ts-ignore
995
1155
  return invoke$1('ExtensionManagement.getExtension', id);
996
1156
  };
997
1157
 
998
1158
  const {
999
- invoke} = create(SharedProcess);
1159
+ invoke,
1160
+ set: set$1
1161
+ } = create$1(SharedProcess);
1162
+
1163
+ const create = () => {
1164
+ return {
1165
+ finished: false
1166
+ };
1167
+ };
1168
+ const cancel = token => {
1169
+ token.finished = true;
1170
+ };
1171
+ const isCanceled = token => {
1172
+ return token.finished;
1173
+ };
1174
+
1175
+ const baseName = path => {
1176
+ const slashIndex = path.lastIndexOf('/');
1177
+ return path.slice(slashIndex + 1);
1178
+ };
1179
+ const getExtensionId = extension => {
1180
+ if (extension && extension.id) {
1181
+ return extension.id;
1182
+ }
1183
+ if (extension && extension.path) {
1184
+ return baseName(extension.path);
1185
+ }
1186
+ return '<unknown>';
1187
+ };
1188
+
1189
+ const isImportErrorChrome = error => {
1190
+ return Boolean(error && error instanceof Error && error.message.startsWith('Failed to fetch dynamically imported module'));
1191
+ };
1192
+
1193
+ const isImportErrorFirefox = error => {
1194
+ return Boolean(error && error instanceof TypeError && error.message === 'error loading dynamically imported module');
1195
+ };
1196
+
1197
+ const isSyntaxError = error => {
1198
+ return error instanceof SyntaxError;
1199
+ };
1200
+
1201
+ const isImportError = error => {
1202
+ return isImportErrorChrome(error) || isImportErrorFirefox(error) || isSyntaxError(error);
1203
+ };
1204
+
1205
+ const states = Object.create(null);
1206
+ const update$1 = (id, update) => {
1207
+ states[id] = {
1208
+ ...states[id],
1209
+ ...update
1210
+ };
1211
+ };
1212
+
1213
+ const Activating = 2;
1214
+ const Activated = 3;
1215
+ const Error$1 = 4;
1216
+
1217
+ const sleep = duration => {
1218
+ const {
1219
+ promise,
1220
+ resolve
1221
+ } = Promise.withResolvers();
1222
+ setTimeout(resolve, duration);
1223
+ return promise;
1224
+ };
1225
+
1226
+ const NotFound = 404;
1227
+
1228
+ const tryToGetActualImportErrorMessage = async (url, error) => {
1229
+ let response;
1230
+ try {
1231
+ response = await fetch(url);
1232
+ } catch (error) {
1233
+ return `Failed to import ${url}: ${error}`;
1234
+ }
1235
+ if (response.ok) {
1236
+ throw new Error(`Failed to import ${url}: Unknown Error`);
1237
+ }
1238
+ switch (response.status) {
1239
+ case NotFound:
1240
+ throw new Error(`Failed to import ${url}: Not found (404)`);
1241
+ default:
1242
+ return `Failed to import ${url}: ${error}`;
1243
+ }
1244
+ };
1245
+
1246
+ // TODO make activation timeout configurable or remove it.
1247
+ // some extension might do workspace indexing which could take some time
1248
+ const activationTimeout = 10_000;
1249
+ const rejectAfterTimeout = async (timeout, token) => {
1250
+ await sleep(timeout);
1251
+ if (isCanceled(token)) {
1252
+ return;
1253
+ }
1254
+ throw new Error(`Activation timeout of ${timeout}ms exceeded`);
1255
+ };
1256
+ const activate = async extension => {};
1257
+ const activateExtension2 = async (extensionId, extension, absolutePath) => {
1258
+ const token = create();
1259
+ try {
1260
+ const startTime = performance.now();
1261
+ update$1(extensionId, {
1262
+ activationStartTime: startTime,
1263
+ status: Activating
1264
+ });
1265
+ await Promise.race([activate(extension), rejectAfterTimeout(activationTimeout, token)]);
1266
+ const endTime = performance.now();
1267
+ const time = endTime - startTime;
1268
+ update$1(extensionId, {
1269
+ activationEndTime: endTime,
1270
+ activationTime: time,
1271
+ status: Activated
1272
+ });
1273
+ } catch (error) {
1274
+ const id = getExtensionId(extension);
1275
+ if (isImportError(error)) {
1276
+ const actualErrorMessage = await tryToGetActualImportErrorMessage(absolutePath, error);
1277
+ throw new Error(`Failed to activate extension ${id}: ${actualErrorMessage}`);
1278
+ }
1279
+ update$1(extensionId, {
1280
+ status: Error$1 // TODO maybe store error also in runtime status state
1281
+ });
1282
+ throw new VError(error, `Failed to activate extension ${id}`);
1283
+ } finally {
1284
+ cancel(token);
1285
+ }
1286
+ };
1000
1287
 
1001
1288
  const invalidateExtensionsCache = async () => {
1002
1289
  await invoke$1('ExtensionManagement.invalidateExtensionsCache');
1003
1290
  };
1004
1291
 
1005
1292
  let state = {
1006
- disabledIds: []
1293
+ disabledIds: [],
1294
+ platform: 0
1007
1295
  };
1008
1296
  const set = newState => {
1009
1297
  state = newState;
1010
1298
  };
1299
+ const update = newState => {
1300
+ const fullNewState = {
1301
+ ...state,
1302
+ ...newState
1303
+ };
1304
+ state = fullNewState;
1305
+ };
1011
1306
  const get = () => {
1012
1307
  return state;
1013
1308
  };
1014
1309
 
1015
1310
  const disableExtension = async (id, isTest) => {
1311
+ const oldState = get();
1016
1312
  try {
1017
1313
  if (isTest) {
1018
- const oldState = get();
1019
1314
  const newState = {
1020
1315
  ...oldState,
1021
1316
  disabledIds: [...oldState.disabledIds, id]
@@ -1032,22 +1327,34 @@ const disableExtension = async (id, isTest) => {
1032
1327
  };
1033
1328
 
1034
1329
  const enableExtension = async (id, isTest) => {
1035
- try {
1036
- if (isTest) {
1037
- const oldState = get();
1038
- const newState = {
1039
- ...oldState,
1040
- disabledIds: oldState.disabledIds.filter(existing => existing !== id)
1041
- };
1042
- set(newState);
1043
- } else {
1044
- await invoke('ExtensionManagement.enable', /* id */id);
1330
+ const oldState = get();
1331
+ const {
1332
+ platform
1333
+ } = oldState;
1334
+ if (platform === Remote || platform === Electron) {
1335
+ const disabledExtensionsJsonPath = await invoke$1('PlatformPaths.getBuiltinExtensionsJsonPath');
1336
+ const exists$1 = await exists(disabledExtensionsJsonPath);
1337
+ if (!exists$1) {
1338
+ return undefined;
1045
1339
  }
1046
- await invalidateExtensionsCache();
1047
- return undefined;
1048
- } catch (error) {
1049
- return error;
1340
+ const content = await readFile(disabledExtensionsJsonPath);
1341
+ const parsed = JSON.parse(content);
1342
+ const oldDisabled = parsed.disabledExtensions || [];
1343
+ const newDisabled = oldDisabled.filter(item => item !== id);
1344
+ const newData = {
1345
+ disabledExtensions: newDisabled
1346
+ };
1347
+ const newContent = JSON.stringify(newData, null, 2) + '\n';
1348
+ await writeFile(disabledExtensionsJsonPath, newContent);
1349
+ }
1350
+ if (isTest) {
1351
+ const newState = {
1352
+ ...oldState,
1353
+ disabledIds: oldState.disabledIds.filter(existing => existing !== id)
1354
+ };
1355
+ set(newState);
1050
1356
  }
1357
+ return undefined;
1051
1358
  };
1052
1359
 
1053
1360
  const getExtension = async id => {
@@ -1056,6 +1363,14 @@ const getExtension = async id => {
1056
1363
  return extension;
1057
1364
  };
1058
1365
 
1366
+ const getAllExtensions = async () => {
1367
+ const state = get();
1368
+ if (state.platform === Web) {
1369
+ return [];
1370
+ }
1371
+ return invoke(/* ExtensionManagement.getAllExtensions */'ExtensionManagement.getAllExtensions');
1372
+ };
1373
+
1059
1374
  const commandMapRef = {};
1060
1375
 
1061
1376
  const handleMessagePort = async port => {
@@ -1065,8 +1380,48 @@ const handleMessagePort = async port => {
1065
1380
  });
1066
1381
  };
1067
1382
 
1068
- const initialize = async () => {
1383
+ const initializeFileSystemWorker = async () => {
1384
+ const rpc = await TransferMessagePortRpcParent.create({
1385
+ commandMap: commandMapRef,
1386
+ async send(port) {
1387
+ await sendMessagePortToFileSystemWorker(port, 0);
1388
+ }
1389
+ });
1390
+ set$3(rpc);
1391
+ };
1392
+
1393
+ const getRpc = async platform => {
1069
1394
  // TODO create connection to shared process
1395
+ if (platform === Remote) {
1396
+ const rpc = await WebSocketRpcParent2.create({
1397
+ commandMap: commandMapRef,
1398
+ type: 'shared-process'
1399
+ });
1400
+ return rpc;
1401
+ }
1402
+ if (platform === Electron) {
1403
+ const rpc = TransferMessagePortRpcParent.create({
1404
+ commandMap: commandMapRef,
1405
+ async send(port) {
1406
+ await sendMessagePortToSharedProcess(port);
1407
+ }
1408
+ });
1409
+ return rpc;
1410
+ }
1411
+ return undefined;
1412
+ };
1413
+ const initializeSharedProcess = async platform => {
1414
+ const rpc = await getRpc(platform);
1415
+ if (rpc) {
1416
+ set$1(rpc);
1417
+ }
1418
+ };
1419
+
1420
+ const initialize = async platform => {
1421
+ update({
1422
+ platform
1423
+ });
1424
+ await Promise.all([initializeFileSystemWorker(), initializeSharedProcess(platform)]);
1070
1425
  };
1071
1426
 
1072
1427
  const installExtension = async () => {
@@ -1078,8 +1433,10 @@ const uninstallExtension = async () => {
1078
1433
  };
1079
1434
 
1080
1435
  const commandMap = {
1436
+ 'Extensions.activate2': activateExtension2,
1081
1437
  'Extensions.disable': disableExtension,
1082
1438
  'Extensions.enable': enableExtension,
1439
+ 'Extensions.getAllExtensions': getAllExtensions,
1083
1440
  'Extensions.getExtension': getExtension,
1084
1441
  'Extensions.handleMessagePort': handleMessagePort,
1085
1442
  'Extensions.initialize': initialize,
@@ -1092,7 +1449,7 @@ const listen = async () => {
1092
1449
  const rpc = await WebWorkerRpcClient.create({
1093
1450
  commandMap: commandMap
1094
1451
  });
1095
- set$1(rpc);
1452
+ set$2(rpc);
1096
1453
  };
1097
1454
 
1098
1455
  const main = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-management-worker",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Webworker for the Extension Management functionality in Lvce Editor.",
5
5
  "keywords": [
6
6
  "web-worker"