@hangox/mg-cli 1.0.8 → 1.0.9

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/dist/server.js CHANGED
@@ -41,6 +41,7 @@ var ErrorNames = {
41
41
  ["E015" /* SERVER_START_FAILED */]: "SERVER_START_FAILED",
42
42
  ["E016" /* SERVER_ALREADY_RUNNING */]: "SERVER_ALREADY_RUNNING",
43
43
  ["E017" /* CONNECTION_LOST */]: "CONNECTION_LOST",
44
+ ["E018" /* NO_EXTENSION_CONNECTED */]: "NO_EXTENSION_CONNECTED",
44
45
  ["E099" /* UNKNOWN_ERROR */]: "UNKNOWN_ERROR"
45
46
  };
46
47
  var ErrorMessages = {
@@ -61,6 +62,7 @@ var ErrorMessages = {
61
62
  ["E015" /* SERVER_START_FAILED */]: "\u81EA\u52A8\u542F\u52A8 Server \u5931\u8D25",
62
63
  ["E016" /* SERVER_ALREADY_RUNNING */]: "Server \u5DF2\u5728\u8FD0\u884C\u4E2D",
63
64
  ["E017" /* CONNECTION_LOST */]: "\u8FDE\u63A5\u65AD\u5F00",
65
+ ["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",
64
66
  ["E099" /* UNKNOWN_ERROR */]: "\u672A\u77E5\u9519\u8BEF"
65
67
  };
66
68
  var MGError = class extends Error {
@@ -210,6 +212,12 @@ var ConnectionManager = class {
210
212
  providers = /* @__PURE__ */ new Map();
211
213
  /** Consumer 连接 */
212
214
  consumers = /* @__PURE__ */ new Map();
215
+ /** Chrome 扩展连接(按扩展 ID 索引) */
216
+ chromeExtensions = /* @__PURE__ */ new Map();
217
+ /** 扩展序号映射(扩展 ID → 序号) */
218
+ extensionIndexMap = /* @__PURE__ */ new Map();
219
+ /** 下一个可用的扩展序号 */
220
+ nextExtensionIndex = 1;
213
221
  /** 所有连接(按 ID 索引) */
214
222
  allConnections = /* @__PURE__ */ new Map();
215
223
  /** 心跳检查定时器 */
@@ -304,6 +312,16 @@ var ConnectionManager = class {
304
312
  } else if (connectionInfo.type === "consumer" /* CONSUMER */) {
305
313
  this.consumers.delete(connectionId);
306
314
  this.logger.info(`Consumer \u65AD\u5F00: ${connectionId}`);
315
+ } else if (connectionInfo.type === "chrome_extension" /* CHROME_EXTENSION */) {
316
+ for (const [extensionId, extWs] of this.chromeExtensions) {
317
+ if (extWs.connectionId === connectionId) {
318
+ const index = this.extensionIndexMap.get(extensionId);
319
+ this.chromeExtensions.delete(extensionId);
320
+ this.extensionIndexMap.delete(extensionId);
321
+ this.logger.info(`Chrome \u6269\u5C55\u65AD\u5F00: ${extensionId} (\u5E8F\u53F7: #${index})`);
322
+ break;
323
+ }
324
+ }
307
325
  }
308
326
  }
309
327
  /**
@@ -357,6 +375,7 @@ var ConnectionManager = class {
357
375
  return {
358
376
  providers: providerCount,
359
377
  consumers: this.consumers.size,
378
+ extensions: this.chromeExtensions.size,
360
379
  total: this.allConnections.size
361
380
  };
362
381
  }
@@ -366,6 +385,48 @@ var ConnectionManager = class {
366
385
  getConnectedPageUrls() {
367
386
  return Array.from(this.providers.keys());
368
387
  }
388
+ /**
389
+ * 添加 Chrome 扩展连接
390
+ */
391
+ addChromeExtension(ws, extensionId) {
392
+ const managedWs = this.addConnection(ws, "chrome_extension" /* CHROME_EXTENSION */);
393
+ const index = this.nextExtensionIndex++;
394
+ this.extensionIndexMap.set(extensionId, index);
395
+ this.chromeExtensions.set(extensionId, managedWs);
396
+ this.logger.info(`Chrome \u6269\u5C55\u8FDE\u63A5: ${extensionId} (\u5206\u914D\u5E8F\u53F7: #${index})`);
397
+ return managedWs;
398
+ }
399
+ /**
400
+ * 根据序号查找扩展
401
+ */
402
+ findExtensionByIndex(index) {
403
+ for (const [extensionId, extIndex] of this.extensionIndexMap) {
404
+ if (extIndex === index) {
405
+ return this.chromeExtensions.get(extensionId);
406
+ }
407
+ }
408
+ return void 0;
409
+ }
410
+ /**
411
+ * 获取第一个扩展
412
+ */
413
+ getFirstExtension() {
414
+ return this.chromeExtensions.values().next().value;
415
+ }
416
+ /**
417
+ * 获取所有扩展信息
418
+ */
419
+ getAllExtensions() {
420
+ const result = [];
421
+ for (const [extensionId, ws] of this.chromeExtensions) {
422
+ const index = this.extensionIndexMap.get(extensionId);
423
+ if (index !== void 0) {
424
+ result.push({ index, extensionId, ws });
425
+ }
426
+ }
427
+ result.sort((a, b) => a.index - b.index);
428
+ return result;
429
+ }
369
430
  /**
370
431
  * 关闭所有连接
371
432
  */
@@ -377,6 +438,8 @@ var ConnectionManager = class {
377
438
  }
378
439
  this.providers.clear();
379
440
  this.consumers.clear();
441
+ this.chromeExtensions.clear();
442
+ this.extensionIndexMap.clear();
380
443
  this.allConnections.clear();
381
444
  }
382
445
  };
@@ -494,6 +557,24 @@ var RequestHandler = class {
494
557
  this.logger.error(`\u53D1\u9001\u9519\u8BEF\u54CD\u5E94\u5931\u8D25: ${requestId}`, err);
495
558
  }
496
559
  }
560
+ /**
561
+ * 注册待处理请求(供外部使用,如 OPEN_PAGE)
562
+ * @param requestId 请求 ID
563
+ * @param consumer 发起请求的 Consumer
564
+ * @param sendCallback 发送请求的回调函数
565
+ */
566
+ registerPendingRequest(requestId, consumer, sendCallback) {
567
+ const timer = setTimeout(() => {
568
+ this.handleTimeout(requestId);
569
+ }, REQUEST_TIMEOUT);
570
+ this.pendingRequests.set(requestId, {
571
+ id: requestId,
572
+ consumer,
573
+ timer,
574
+ timestamp: Date.now()
575
+ });
576
+ sendCallback();
577
+ }
497
578
  /**
498
579
  * 清理特定连接的所有待处理请求
499
580
  */
@@ -666,12 +747,22 @@ var MGServer = class {
666
747
  */
667
748
  handleRegister(ws, message) {
668
749
  const { connectionType, pageUrl, pageId } = message.data;
669
- const managedWs = this.connectionManager.addConnection(
670
- ws,
671
- connectionType,
672
- pageUrl,
673
- pageId
674
- );
750
+ const extensionId = message.data.extensionId;
751
+ let managedWs;
752
+ let extensionIndex;
753
+ if (connectionType === "chrome_extension" /* CHROME_EXTENSION */ && extensionId) {
754
+ managedWs = this.connectionManager.addChromeExtension(ws, extensionId);
755
+ const exts = this.connectionManager.getAllExtensions();
756
+ const ext = exts.find((e) => e.extensionId === extensionId);
757
+ extensionIndex = ext?.index;
758
+ } else {
759
+ managedWs = this.connectionManager.addConnection(
760
+ ws,
761
+ connectionType,
762
+ pageUrl,
763
+ pageId
764
+ );
765
+ }
675
766
  const ack = {
676
767
  id: message.id || "",
677
768
  type: "register_ack" /* REGISTER_ACK */,
@@ -679,7 +770,8 @@ var MGServer = class {
679
770
  data: {
680
771
  connectionId: managedWs.connectionId,
681
772
  pageUrl,
682
- serverVersion: getVersion()
773
+ serverVersion: getVersion(),
774
+ ...extensionIndex !== void 0 && { extensionIndex }
683
775
  }
684
776
  };
685
777
  ws.send(JSON.stringify(ack));
@@ -696,6 +788,15 @@ var MGServer = class {
696
788
  case "get_server_status" /* GET_SERVER_STATUS */:
697
789
  this.handleGetServerStatus(ws, message);
698
790
  break;
791
+ case "list_extensions" /* LIST_EXTENSIONS */:
792
+ this.handleListExtensions(ws, message);
793
+ break;
794
+ case "open_page" /* OPEN_PAGE */:
795
+ this.handleOpenPage(ws, message);
796
+ break;
797
+ case "navigate_to_node" /* NAVIGATE_TO_NODE */:
798
+ this.handleNavigateToNode(ws, message);
799
+ break;
699
800
  case "response" /* RESPONSE */:
700
801
  case "error" /* ERROR */:
701
802
  this.requestHandler.handleResponse(message);
@@ -728,6 +829,13 @@ var MGServer = class {
728
829
  connectedAt: info.connectedAt.toISOString(),
729
830
  lastActiveAt: info.lastActiveAt.toISOString()
730
831
  }));
832
+ const extensions = this.connectionManager.getAllExtensions();
833
+ const connectedExtensions = extensions.map((ext) => ({
834
+ index: ext.index,
835
+ extensionId: ext.extensionId,
836
+ connectedAt: ext.ws.connectionInfo.connectedAt.toISOString(),
837
+ lastActiveAt: ext.ws.connectionInfo.lastActiveAt.toISOString()
838
+ }));
731
839
  const uptimeMs = this.startedAt ? Date.now() - this.startedAt.getTime() : 0;
732
840
  const statusData = {
733
841
  running: this.isRunning,
@@ -737,7 +845,8 @@ var MGServer = class {
737
845
  uptime: formatDuration(uptimeMs),
738
846
  version: getVersion(),
739
847
  stats,
740
- connectedPages
848
+ connectedPages,
849
+ connectedExtensions
741
850
  };
742
851
  const response = {
743
852
  id: message.id || "",
@@ -748,6 +857,156 @@ var MGServer = class {
748
857
  ws.send(JSON.stringify(response));
749
858
  this.logger.info("\u8FD4\u56DE Server \u72B6\u6001\u4FE1\u606F");
750
859
  }
860
+ /**
861
+ * 处理扩展列表查询
862
+ */
863
+ handleListExtensions(ws, message) {
864
+ const extensions = this.connectionManager.getAllExtensions();
865
+ const extensionList = extensions.map((ext) => ({
866
+ index: ext.index,
867
+ extensionId: ext.extensionId,
868
+ connectedAt: ext.ws.connectionInfo.connectedAt.toISOString(),
869
+ lastActiveAt: ext.ws.connectionInfo.lastActiveAt.toISOString()
870
+ }));
871
+ const response = {
872
+ id: message.id || "",
873
+ type: "response" /* RESPONSE */,
874
+ success: true,
875
+ data: {
876
+ extensions: extensionList,
877
+ totalCount: extensionList.length
878
+ }
879
+ };
880
+ ws.send(JSON.stringify(response));
881
+ this.logger.info(`\u8FD4\u56DE\u6269\u5C55\u5217\u8868\uFF0C\u5171 ${extensionList.length} \u4E2A\u6269\u5C55`);
882
+ }
883
+ /**
884
+ * 处理打开页面请求
885
+ */
886
+ handleOpenPage(ws, message) {
887
+ const params = message.params;
888
+ const requestId = message.id || "";
889
+ if (!params?.url) {
890
+ const errorResponse = {
891
+ id: requestId,
892
+ type: "error" /* ERROR */,
893
+ success: false,
894
+ error: {
895
+ code: "E011" /* INVALID_PARAMS */,
896
+ name: "INVALID_PARAMS",
897
+ message: "\u7F3A\u5C11 url \u53C2\u6570"
898
+ }
899
+ };
900
+ ws.send(JSON.stringify(errorResponse));
901
+ return;
902
+ }
903
+ const targetIndex = params.extensionIndex || 1;
904
+ const targetExtension = this.connectionManager.findExtensionByIndex(targetIndex);
905
+ if (!targetExtension) {
906
+ const errorResponse = {
907
+ id: requestId,
908
+ type: "error" /* ERROR */,
909
+ success: false,
910
+ error: {
911
+ code: "E018" /* NO_EXTENSION_CONNECTED */,
912
+ name: "NO_EXTENSION_CONNECTED",
913
+ 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`
914
+ }
915
+ };
916
+ ws.send(JSON.stringify(errorResponse));
917
+ this.logger.warn(`\u672A\u627E\u5230\u6269\u5C55\u5B9E\u4F8B #${targetIndex}`);
918
+ return;
919
+ }
920
+ const forwardMessage = {
921
+ id: requestId,
922
+ type: "open_page" /* OPEN_PAGE */,
923
+ params: { url: params.url }
924
+ };
925
+ this.requestHandler.registerPendingRequest(requestId, ws, () => {
926
+ try {
927
+ targetExtension.send(JSON.stringify(forwardMessage));
928
+ this.logger.info(`\u8F6C\u53D1 OPEN_PAGE \u8BF7\u6C42\u5230\u6269\u5C55 #${targetIndex}: ${params.url}`);
929
+ } catch (error) {
930
+ this.logger.error(`\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25: ${error}`);
931
+ const errorResponse = {
932
+ id: requestId,
933
+ type: "error" /* ERROR */,
934
+ success: false,
935
+ error: {
936
+ code: "E001" /* CONNECTION_FAILED */,
937
+ name: "CONNECTION_FAILED",
938
+ message: "\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25"
939
+ }
940
+ };
941
+ ws.send(JSON.stringify(errorResponse));
942
+ }
943
+ });
944
+ }
945
+ /**
946
+ * 处理节点导航请求
947
+ */
948
+ handleNavigateToNode(ws, message) {
949
+ const params = message.params;
950
+ const requestId = message.id || "";
951
+ if (!params?.pageUrl || !params?.nodeId) {
952
+ const errorResponse = {
953
+ id: requestId,
954
+ type: "error" /* ERROR */,
955
+ success: false,
956
+ error: {
957
+ code: "E011" /* INVALID_PARAMS */,
958
+ name: "INVALID_PARAMS",
959
+ message: "\u7F3A\u5C11 pageUrl \u6216 nodeId \u53C2\u6570"
960
+ }
961
+ };
962
+ ws.send(JSON.stringify(errorResponse));
963
+ return;
964
+ }
965
+ const targetIndex = params.extensionIndex || 1;
966
+ const targetExtension = this.connectionManager.findExtensionByIndex(targetIndex);
967
+ if (!targetExtension) {
968
+ const errorResponse = {
969
+ id: requestId,
970
+ type: "error" /* ERROR */,
971
+ success: false,
972
+ error: {
973
+ code: "E018" /* NO_EXTENSION_CONNECTED */,
974
+ name: "NO_EXTENSION_CONNECTED",
975
+ 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`
976
+ }
977
+ };
978
+ ws.send(JSON.stringify(errorResponse));
979
+ this.logger.warn(`\u672A\u627E\u5230\u6269\u5C55\u5B9E\u4F8B #${targetIndex}`);
980
+ return;
981
+ }
982
+ const forwardMessage = {
983
+ id: requestId,
984
+ type: "navigate_to_node" /* NAVIGATE_TO_NODE */,
985
+ params: {
986
+ pageUrl: params.pageUrl,
987
+ nodeId: params.nodeId
988
+ }
989
+ };
990
+ this.requestHandler.registerPendingRequest(requestId, ws, () => {
991
+ try {
992
+ targetExtension.send(JSON.stringify(forwardMessage));
993
+ this.logger.info(`\u8F6C\u53D1 NAVIGATE_TO_NODE \u8BF7\u6C42\u5230\u6269\u5C55 #${targetIndex}: ${params.pageUrl} -> ${params.nodeId}`);
994
+ } catch (error) {
995
+ this.logger.error(`\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25: ${error}`);
996
+ const errorResponse = {
997
+ id: requestId,
998
+ type: "error" /* ERROR */,
999
+ success: false,
1000
+ error: {
1001
+ code: "E001" /* CONNECTION_FAILED */,
1002
+ name: "CONNECTION_FAILED",
1003
+ message: "\u8F6C\u53D1\u8BF7\u6C42\u5931\u8D25"
1004
+ }
1005
+ };
1006
+ ws.send(JSON.stringify(errorResponse));
1007
+ }
1008
+ });
1009
+ }
751
1010
  /**
752
1011
  * 停止服务器
753
1012
  */