@hangox/mg-cli 1.0.8 → 1.1.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.
@@ -122,6 +122,7 @@ var ErrorNames = {
122
122
  ["E015" /* SERVER_START_FAILED */]: "SERVER_START_FAILED",
123
123
  ["E016" /* SERVER_ALREADY_RUNNING */]: "SERVER_ALREADY_RUNNING",
124
124
  ["E017" /* CONNECTION_LOST */]: "CONNECTION_LOST",
125
+ ["E018" /* NO_EXTENSION_CONNECTED */]: "NO_EXTENSION_CONNECTED",
125
126
  ["E099" /* UNKNOWN_ERROR */]: "UNKNOWN_ERROR"
126
127
  };
127
128
  var ErrorMessages = {
@@ -142,6 +143,7 @@ var ErrorMessages = {
142
143
  ["E015" /* SERVER_START_FAILED */]: "\u81EA\u52A8\u542F\u52A8 Server \u5931\u8D25",
143
144
  ["E016" /* SERVER_ALREADY_RUNNING */]: "Server \u5DF2\u5728\u8FD0\u884C\u4E2D",
144
145
  ["E017" /* CONNECTION_LOST */]: "\u8FDE\u63A5\u65AD\u5F00",
146
+ ["E018" /* NO_EXTENSION_CONNECTED */]: "\u6CA1\u6709 Chrome \u6269\u5C55\u8FDE\u63A5\u5230 Server\u3002\u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u5E76\u5B89\u88C5\u4E86 MG Plugin",
145
147
  ["E099" /* UNKNOWN_ERROR */]: "\u672A\u77E5\u9519\u8BEF"
146
148
  };
147
149
  var MGError = class extends Error {
@@ -255,6 +257,12 @@ var ConnectionManager = class {
255
257
  providers = /* @__PURE__ */ new Map();
256
258
  /** Consumer 连接 */
257
259
  consumers = /* @__PURE__ */ new Map();
260
+ /** Chrome 扩展连接(按扩展 ID 索引) */
261
+ chromeExtensions = /* @__PURE__ */ new Map();
262
+ /** 扩展序号映射(扩展 ID → 序号) */
263
+ extensionIndexMap = /* @__PURE__ */ new Map();
264
+ /** 下一个可用的扩展序号 */
265
+ nextExtensionIndex = 1;
258
266
  /** 所有连接(按 ID 索引) */
259
267
  allConnections = /* @__PURE__ */ new Map();
260
268
  /** 心跳检查定时器 */
@@ -349,6 +357,16 @@ var ConnectionManager = class {
349
357
  } else if (connectionInfo.type === "consumer" /* CONSUMER */) {
350
358
  this.consumers.delete(connectionId);
351
359
  this.logger.info(`Consumer \u65AD\u5F00: ${connectionId}`);
360
+ } else if (connectionInfo.type === "chrome_extension" /* CHROME_EXTENSION */) {
361
+ for (const [extensionId, extWs] of this.chromeExtensions) {
362
+ if (extWs.connectionId === connectionId) {
363
+ const index = this.extensionIndexMap.get(extensionId);
364
+ this.chromeExtensions.delete(extensionId);
365
+ this.extensionIndexMap.delete(extensionId);
366
+ this.logger.info(`Chrome \u6269\u5C55\u65AD\u5F00: ${extensionId} (\u5E8F\u53F7: #${index})`);
367
+ break;
368
+ }
369
+ }
352
370
  }
353
371
  }
354
372
  /**
@@ -402,6 +420,7 @@ var ConnectionManager = class {
402
420
  return {
403
421
  providers: providerCount,
404
422
  consumers: this.consumers.size,
423
+ extensions: this.chromeExtensions.size,
405
424
  total: this.allConnections.size
406
425
  };
407
426
  }
@@ -411,6 +430,48 @@ var ConnectionManager = class {
411
430
  getConnectedPageUrls() {
412
431
  return Array.from(this.providers.keys());
413
432
  }
433
+ /**
434
+ * 添加 Chrome 扩展连接
435
+ */
436
+ addChromeExtension(ws, extensionId) {
437
+ const managedWs = this.addConnection(ws, "chrome_extension" /* CHROME_EXTENSION */);
438
+ const index = this.nextExtensionIndex++;
439
+ this.extensionIndexMap.set(extensionId, index);
440
+ this.chromeExtensions.set(extensionId, managedWs);
441
+ this.logger.info(`Chrome \u6269\u5C55\u8FDE\u63A5: ${extensionId} (\u5206\u914D\u5E8F\u53F7: #${index})`);
442
+ return managedWs;
443
+ }
444
+ /**
445
+ * 根据序号查找扩展
446
+ */
447
+ findExtensionByIndex(index) {
448
+ for (const [extensionId, extIndex] of this.extensionIndexMap) {
449
+ if (extIndex === index) {
450
+ return this.chromeExtensions.get(extensionId);
451
+ }
452
+ }
453
+ return void 0;
454
+ }
455
+ /**
456
+ * 获取第一个扩展
457
+ */
458
+ getFirstExtension() {
459
+ return this.chromeExtensions.values().next().value;
460
+ }
461
+ /**
462
+ * 获取所有扩展信息
463
+ */
464
+ getAllExtensions() {
465
+ const result = [];
466
+ for (const [extensionId, ws] of this.chromeExtensions) {
467
+ const index = this.extensionIndexMap.get(extensionId);
468
+ if (index !== void 0) {
469
+ result.push({ index, extensionId, ws });
470
+ }
471
+ }
472
+ result.sort((a, b) => a.index - b.index);
473
+ return result;
474
+ }
414
475
  /**
415
476
  * 关闭所有连接
416
477
  */
@@ -422,6 +483,8 @@ var ConnectionManager = class {
422
483
  }
423
484
  this.providers.clear();
424
485
  this.consumers.clear();
486
+ this.chromeExtensions.clear();
487
+ this.extensionIndexMap.clear();
425
488
  this.allConnections.clear();
426
489
  }
427
490
  };
@@ -539,6 +602,24 @@ var RequestHandler = class {
539
602
  this.logger.error(`\u53D1\u9001\u9519\u8BEF\u54CD\u5E94\u5931\u8D25: ${requestId}`, err);
540
603
  }
541
604
  }
605
+ /**
606
+ * 注册待处理请求(供外部使用,如 OPEN_PAGE)
607
+ * @param requestId 请求 ID
608
+ * @param consumer 发起请求的 Consumer
609
+ * @param sendCallback 发送请求的回调函数
610
+ */
611
+ registerPendingRequest(requestId, consumer, sendCallback) {
612
+ const timer = setTimeout(() => {
613
+ this.handleTimeout(requestId);
614
+ }, REQUEST_TIMEOUT);
615
+ this.pendingRequests.set(requestId, {
616
+ id: requestId,
617
+ consumer,
618
+ timer,
619
+ timestamp: Date.now()
620
+ });
621
+ sendCallback();
622
+ }
542
623
  /**
543
624
  * 清理特定连接的所有待处理请求
544
625
  */
@@ -711,12 +792,22 @@ var MGServer = class {
711
792
  */
712
793
  handleRegister(ws, message) {
713
794
  const { connectionType, pageUrl, pageId } = message.data;
714
- const managedWs = this.connectionManager.addConnection(
715
- ws,
716
- connectionType,
717
- pageUrl,
718
- pageId
719
- );
795
+ const extensionId = message.data.extensionId;
796
+ let managedWs;
797
+ let extensionIndex;
798
+ if (connectionType === "chrome_extension" /* CHROME_EXTENSION */ && extensionId) {
799
+ managedWs = this.connectionManager.addChromeExtension(ws, extensionId);
800
+ const exts = this.connectionManager.getAllExtensions();
801
+ const ext = exts.find((e) => e.extensionId === extensionId);
802
+ extensionIndex = ext?.index;
803
+ } else {
804
+ managedWs = this.connectionManager.addConnection(
805
+ ws,
806
+ connectionType,
807
+ pageUrl,
808
+ pageId
809
+ );
810
+ }
720
811
  const ack = {
721
812
  id: message.id || "",
722
813
  type: "register_ack" /* REGISTER_ACK */,
@@ -724,7 +815,8 @@ var MGServer = class {
724
815
  data: {
725
816
  connectionId: managedWs.connectionId,
726
817
  pageUrl,
727
- serverVersion: getVersion()
818
+ serverVersion: getVersion(),
819
+ ...extensionIndex !== void 0 && { extensionIndex }
728
820
  }
729
821
  };
730
822
  ws.send(JSON.stringify(ack));
@@ -741,6 +833,15 @@ var MGServer = class {
741
833
  case "get_server_status" /* GET_SERVER_STATUS */:
742
834
  this.handleGetServerStatus(ws, message);
743
835
  break;
836
+ case "list_extensions" /* LIST_EXTENSIONS */:
837
+ this.handleListExtensions(ws, message);
838
+ break;
839
+ case "open_page" /* OPEN_PAGE */:
840
+ this.handleOpenPage(ws, message);
841
+ break;
842
+ case "navigate_to_node" /* NAVIGATE_TO_NODE */:
843
+ this.handleNavigateToNode(ws, message);
844
+ break;
744
845
  case "response" /* RESPONSE */:
745
846
  case "error" /* ERROR */:
746
847
  this.requestHandler.handleResponse(message);
@@ -773,6 +874,13 @@ var MGServer = class {
773
874
  connectedAt: info.connectedAt.toISOString(),
774
875
  lastActiveAt: info.lastActiveAt.toISOString()
775
876
  }));
877
+ const extensions = this.connectionManager.getAllExtensions();
878
+ const connectedExtensions = extensions.map((ext) => ({
879
+ index: ext.index,
880
+ extensionId: ext.extensionId,
881
+ connectedAt: ext.ws.connectionInfo.connectedAt.toISOString(),
882
+ lastActiveAt: ext.ws.connectionInfo.lastActiveAt.toISOString()
883
+ }));
776
884
  const uptimeMs = this.startedAt ? Date.now() - this.startedAt.getTime() : 0;
777
885
  const statusData = {
778
886
  running: this.isRunning,
@@ -782,7 +890,8 @@ var MGServer = class {
782
890
  uptime: formatDuration(uptimeMs),
783
891
  version: getVersion(),
784
892
  stats,
785
- connectedPages
893
+ connectedPages,
894
+ connectedExtensions
786
895
  };
787
896
  const response = {
788
897
  id: message.id || "",
@@ -793,6 +902,156 @@ var MGServer = class {
793
902
  ws.send(JSON.stringify(response));
794
903
  this.logger.info("\u8FD4\u56DE Server \u72B6\u6001\u4FE1\u606F");
795
904
  }
905
+ /**
906
+ * 处理扩展列表查询
907
+ */
908
+ handleListExtensions(ws, message) {
909
+ const extensions = this.connectionManager.getAllExtensions();
910
+ const extensionList = extensions.map((ext) => ({
911
+ index: ext.index,
912
+ extensionId: ext.extensionId,
913
+ connectedAt: ext.ws.connectionInfo.connectedAt.toISOString(),
914
+ lastActiveAt: ext.ws.connectionInfo.lastActiveAt.toISOString()
915
+ }));
916
+ const response = {
917
+ id: message.id || "",
918
+ type: "response" /* RESPONSE */,
919
+ success: true,
920
+ data: {
921
+ extensions: extensionList,
922
+ totalCount: extensionList.length
923
+ }
924
+ };
925
+ ws.send(JSON.stringify(response));
926
+ this.logger.info(`\u8FD4\u56DE\u6269\u5C55\u5217\u8868\uFF0C\u5171 ${extensionList.length} \u4E2A\u6269\u5C55`);
927
+ }
928
+ /**
929
+ * 处理打开页面请求
930
+ */
931
+ handleOpenPage(ws, message) {
932
+ const params = message.params;
933
+ const requestId = message.id || "";
934
+ if (!params?.url) {
935
+ const errorResponse = {
936
+ id: requestId,
937
+ type: "error" /* ERROR */,
938
+ success: false,
939
+ error: {
940
+ code: "E011" /* INVALID_PARAMS */,
941
+ name: "INVALID_PARAMS",
942
+ message: "\u7F3A\u5C11 url \u53C2\u6570"
943
+ }
944
+ };
945
+ ws.send(JSON.stringify(errorResponse));
946
+ return;
947
+ }
948
+ const targetIndex = params.extensionIndex || 1;
949
+ const targetExtension = this.connectionManager.findExtensionByIndex(targetIndex);
950
+ if (!targetExtension) {
951
+ const errorResponse = {
952
+ id: requestId,
953
+ type: "error" /* ERROR */,
954
+ success: false,
955
+ error: {
956
+ code: "E018" /* NO_EXTENSION_CONNECTED */,
957
+ name: "NO_EXTENSION_CONNECTED",
958
+ message: targetIndex === 1 ? "\u6CA1\u6709 Chrome \u6269\u5C55\u8FDE\u63A5\u5230 Server\u3002\u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u5E76\u5B89\u88C5\u4E86 MG Plugin" : `\u672A\u627E\u5230\u5E8F\u53F7\u4E3A #${targetIndex} \u7684\u6269\u5C55\u5B9E\u4F8B`
959
+ }
960
+ };
961
+ ws.send(JSON.stringify(errorResponse));
962
+ this.logger.warn(`\u672A\u627E\u5230\u6269\u5C55\u5B9E\u4F8B #${targetIndex}`);
963
+ return;
964
+ }
965
+ const forwardMessage = {
966
+ id: requestId,
967
+ type: "open_page" /* OPEN_PAGE */,
968
+ params: { url: params.url }
969
+ };
970
+ this.requestHandler.registerPendingRequest(requestId, ws, () => {
971
+ try {
972
+ targetExtension.send(JSON.stringify(forwardMessage));
973
+ this.logger.info(`\u8F6C\u53D1 OPEN_PAGE \u8BF7\u6C42\u5230\u6269\u5C55 #${targetIndex}: ${params.url}`);
974
+ } catch (error) {
975
+ this.logger.error(`\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25: ${error}`);
976
+ const errorResponse = {
977
+ id: requestId,
978
+ type: "error" /* ERROR */,
979
+ success: false,
980
+ error: {
981
+ code: "E001" /* CONNECTION_FAILED */,
982
+ name: "CONNECTION_FAILED",
983
+ message: "\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25"
984
+ }
985
+ };
986
+ ws.send(JSON.stringify(errorResponse));
987
+ }
988
+ });
989
+ }
990
+ /**
991
+ * 处理节点导航请求
992
+ */
993
+ handleNavigateToNode(ws, message) {
994
+ const params = message.params;
995
+ const requestId = message.id || "";
996
+ if (!params?.pageUrl || !params?.nodeId) {
997
+ const errorResponse = {
998
+ id: requestId,
999
+ type: "error" /* ERROR */,
1000
+ success: false,
1001
+ error: {
1002
+ code: "E011" /* INVALID_PARAMS */,
1003
+ name: "INVALID_PARAMS",
1004
+ message: "\u7F3A\u5C11 pageUrl \u6216 nodeId \u53C2\u6570"
1005
+ }
1006
+ };
1007
+ ws.send(JSON.stringify(errorResponse));
1008
+ return;
1009
+ }
1010
+ const targetIndex = params.extensionIndex || 1;
1011
+ const targetExtension = this.connectionManager.findExtensionByIndex(targetIndex);
1012
+ if (!targetExtension) {
1013
+ const errorResponse = {
1014
+ id: requestId,
1015
+ type: "error" /* ERROR */,
1016
+ success: false,
1017
+ error: {
1018
+ code: "E018" /* NO_EXTENSION_CONNECTED */,
1019
+ name: "NO_EXTENSION_CONNECTED",
1020
+ message: targetIndex === 1 ? "\u6CA1\u6709 Chrome \u6269\u5C55\u8FDE\u63A5\u5230 Server\u3002\u8BF7\u786E\u4FDD\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u5E76\u5B89\u88C5\u4E86 MG Plugin" : `\u672A\u627E\u5230\u5E8F\u53F7\u4E3A #${targetIndex} \u7684\u6269\u5C55\u5B9E\u4F8B`
1021
+ }
1022
+ };
1023
+ ws.send(JSON.stringify(errorResponse));
1024
+ this.logger.warn(`\u672A\u627E\u5230\u6269\u5C55\u5B9E\u4F8B #${targetIndex}`);
1025
+ return;
1026
+ }
1027
+ const forwardMessage = {
1028
+ id: requestId,
1029
+ type: "navigate_to_node" /* NAVIGATE_TO_NODE */,
1030
+ params: {
1031
+ pageUrl: params.pageUrl,
1032
+ nodeId: params.nodeId
1033
+ }
1034
+ };
1035
+ this.requestHandler.registerPendingRequest(requestId, ws, () => {
1036
+ try {
1037
+ targetExtension.send(JSON.stringify(forwardMessage));
1038
+ this.logger.info(`\u8F6C\u53D1 NAVIGATE_TO_NODE \u8BF7\u6C42\u5230\u6269\u5C55 #${targetIndex}: ${params.pageUrl} -> ${params.nodeId}`);
1039
+ } catch (error) {
1040
+ this.logger.error(`\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25: ${error}`);
1041
+ const errorResponse = {
1042
+ id: requestId,
1043
+ type: "error" /* ERROR */,
1044
+ success: false,
1045
+ error: {
1046
+ code: "E001" /* CONNECTION_FAILED */,
1047
+ name: "CONNECTION_FAILED",
1048
+ message: "\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25"
1049
+ }
1050
+ };
1051
+ ws.send(JSON.stringify(errorResponse));
1052
+ }
1053
+ });
1054
+ }
796
1055
  /**
797
1056
  * 停止服务器
798
1057
  */