@hangox/mg-cli 1.1.1 → 1.1.3

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/index.js CHANGED
@@ -45,6 +45,7 @@ var MessageType = /* @__PURE__ */ ((MessageType2) => {
45
45
  MessageType2["OPEN_PAGE"] = "open_page";
46
46
  MessageType2["NAVIGATE_TO_NODE"] = "navigate_to_node";
47
47
  MessageType2["GET_SERVER_STATUS"] = "get_server_status";
48
+ MessageType2["TRACK_ANALYTICS"] = "track_analytics";
48
49
  MessageType2["RESPONSE"] = "response";
49
50
  MessageType2["ERROR"] = "error";
50
51
  return MessageType2;
@@ -216,6 +217,32 @@ function normalizePageUrl(url) {
216
217
  return url;
217
218
  }
218
219
  }
220
+ function normalizePageUrlWithPageId(url) {
221
+ try {
222
+ let urlObj;
223
+ if (!url.includes("://") && !url.startsWith("//")) {
224
+ urlObj = new URL(`https://${url}`);
225
+ } else {
226
+ urlObj = new URL(url);
227
+ }
228
+ const basePath = `${urlObj.host}${urlObj.pathname}`;
229
+ const pageId = urlObj.searchParams.get("page_id");
230
+ if (pageId) {
231
+ const decodedPageId = decodeURIComponent(pageId);
232
+ return `${basePath}?page_id=${decodedPageId}`;
233
+ }
234
+ return basePath;
235
+ } catch {
236
+ const withoutProtocol = url.replace(/^https?:\/\//, "").replace(/^\/\//, "");
237
+ const pageIdMatch = withoutProtocol.match(/[?&]page_id=([^&#]+)/);
238
+ const basePath = withoutProtocol.split("?")[0].split("#")[0];
239
+ if (pageIdMatch) {
240
+ const decodedPageId = decodeURIComponent(pageIdMatch[1]);
241
+ return `${basePath}?page_id=${decodedPageId}`;
242
+ }
243
+ return basePath;
244
+ }
245
+ }
219
246
  function isDesignPageUrl(url) {
220
247
  return /\/file\/\d+/.test(url);
221
248
  }
@@ -229,17 +256,22 @@ function parseMgpLink(link) {
229
256
  if (questionMarkIndex === -1) {
230
257
  return null;
231
258
  }
232
- const pageUrl = urlPart.slice(0, questionMarkIndex);
259
+ const basePath = urlPart.slice(0, questionMarkIndex);
233
260
  const queryString = urlPart.slice(questionMarkIndex + 1);
234
261
  const params = new URLSearchParams(queryString);
235
262
  const encodedNodeId = params.get("nodeId");
236
263
  const encodedPageId = params.get("pageId");
264
+ const mgPageId = params.get("page_id");
237
265
  if (!encodedNodeId && !encodedPageId) {
238
266
  return null;
239
267
  }
240
268
  if (encodedNodeId && encodedPageId) {
241
269
  return null;
242
270
  }
271
+ let pageUrl = basePath;
272
+ if (mgPageId) {
273
+ pageUrl = `${basePath}?page_id=${mgPageId}`;
274
+ }
243
275
  if (encodedNodeId) {
244
276
  const nodeId = decodeURIComponent(encodedNodeId);
245
277
  if (!/^(\d+:\d+)(\/\d+:\d+)*$/.test(nodeId)) {
@@ -254,10 +286,19 @@ function parseMgpLink(link) {
254
286
  return null;
255
287
  }
256
288
  }
289
+ const childNodeIdsRaw = params.get("childNodeIds");
290
+ let childNodeIds;
291
+ if (childNodeIdsRaw) {
292
+ childNodeIds = childNodeIdsRaw.split(",").map((id) => decodeURIComponent(id));
293
+ if (!childNodeIds.every((id) => /^(\d+:\d+)(\/\d+:\d+)*$/.test(id))) {
294
+ return null;
295
+ }
296
+ }
257
297
  return {
258
298
  pageUrl,
259
299
  nodeId,
260
- nodePath
300
+ nodePath,
301
+ childNodeIds
261
302
  };
262
303
  }
263
304
  if (encodedPageId) {
@@ -276,9 +317,10 @@ function parseMgpLink(link) {
276
317
  }
277
318
  }
278
319
  function generateMgpLink(pageUrl, nodeId, nodePath) {
279
- const normalizedUrl = normalizePageUrl(pageUrl);
320
+ const normalizedUrl = normalizePageUrlWithPageId(pageUrl);
280
321
  const encodedNodeId = encodeURIComponent(nodeId);
281
- let link = `mgp://${normalizedUrl}?nodeId=${encodedNodeId}`;
322
+ const separator = normalizedUrl.includes("?") ? "&" : "?";
323
+ let link = `mgp://${normalizedUrl}${separator}nodeId=${encodedNodeId}`;
282
324
  if (nodePath && nodePath.length > 0) {
283
325
  const encodedNodePath = encodeURIComponent(nodePath.join("/"));
284
326
  link += `&nodePath=${encodedNodePath}`;
@@ -290,6 +332,15 @@ function generatePageLink(pageUrl, pageId) {
290
332
  const encodedPageId = encodeURIComponent(pageId);
291
333
  return `mgp://${normalizedUrl}?pageId=${encodedPageId}`;
292
334
  }
335
+ function generateMultiNodeMgpLink(pageUrl, parentNodeId, childNodeIds) {
336
+ const normalizedUrl = normalizePageUrlWithPageId(pageUrl);
337
+ const encodedParentNodeId = encodeURIComponent(parentNodeId);
338
+ const separator = normalizedUrl.includes("?") ? "&" : "?";
339
+ let link = `mgp://${normalizedUrl}${separator}nodeId=${encodedParentNodeId}`;
340
+ const encodedChildIds = childNodeIds.map((id) => encodeURIComponent(id)).join(",");
341
+ link += `&childNodeIds=${encodedChildIds}`;
342
+ return link;
343
+ }
293
344
  function formatFileSize(bytes) {
294
345
  if (bytes < 1024) {
295
346
  return `${bytes} \u5B57\u8282`;
@@ -408,6 +459,8 @@ var NODE_DEFAULTS = {
408
459
  dashCap: "NONE",
409
460
  fillStyleId: "",
410
461
  strokeStyleId: "",
462
+ strokeFillStyleId: "",
463
+ strokeWidthStyleId: "",
411
464
  // Corner 属性
412
465
  cornerSmooth: 0,
413
466
  cornerRadius: 0,
@@ -415,6 +468,7 @@ var NODE_DEFAULTS = {
415
468
  topRightRadius: 0,
416
469
  bottomLeftRadius: 0,
417
470
  bottomRightRadius: 0,
471
+ cornerRadiusStyleId: "",
418
472
  // Layout 属性
419
473
  rotation: 0,
420
474
  flexGrow: 0,
@@ -430,9 +484,13 @@ var NODE_DEFAULTS = {
430
484
  paddingRight: 0,
431
485
  paddingBottom: 0,
432
486
  paddingLeft: 0,
487
+ paddingStyleId: "",
488
+ spacingStyleId: "",
433
489
  clipsContent: false,
434
490
  itemReverseZIndex: false,
435
491
  strokesIncludedInLayout: false,
492
+ overflowDirection: "NONE",
493
+ gridStyleId: "",
436
494
  // 其他属性
437
495
  componentPropertyReferences: null
438
496
  };
@@ -443,7 +501,8 @@ var EMPTY_ARRAY_FIELDS = [
443
501
  "strokeDashes",
444
502
  "exportSettings",
445
503
  "reactions",
446
- "attachedConnectors"
504
+ "attachedConnectors",
505
+ "layoutGrids"
447
506
  ];
448
507
  function isEmptyArray(value) {
449
508
  return Array.isArray(value) && value.length === 0;
@@ -607,8 +666,8 @@ var ConnectionManager = class {
607
666
  allConnections = /* @__PURE__ */ new Map();
608
667
  /** 心跳检查定时器 */
609
668
  heartbeatTimer = null;
610
- constructor(logger) {
611
- this.logger = logger;
669
+ constructor(logger2) {
670
+ this.logger = logger2;
612
671
  }
613
672
  /**
614
673
  * 启动心跳检查
@@ -835,9 +894,9 @@ var RequestHandler = class {
835
894
  connectionManager;
836
895
  /** 待处理的请求 */
837
896
  pendingRequests = /* @__PURE__ */ new Map();
838
- constructor(connectionManager, logger) {
897
+ constructor(connectionManager, logger2) {
839
898
  this.connectionManager = connectionManager;
840
- this.logger = logger;
899
+ this.logger = logger2;
841
900
  }
842
901
  /**
843
902
  * 处理 Consumer 请求
@@ -1022,6 +1081,60 @@ function isVersionMatch(version1, version2) {
1022
1081
  return version1 === version2;
1023
1082
  }
1024
1083
 
1084
+ // src/server/analytics.ts
1085
+ import { PostHog } from "posthog-node";
1086
+ var POSTHOG_API_KEY = "phc_cSZZIxZOPhWOlsw92Wz8tmKQ5z8eQYsI3m9aM2Ujia9";
1087
+ var POSTHOG_HOST = "https://us.i.posthog.com";
1088
+ var posthogClient = null;
1089
+ var logger = null;
1090
+ function isTelemetryDisabled() {
1091
+ return process.env.MG_TELEMETRY_DISABLED === "1" || process.env.MG_TELEMETRY_DISABLED === "true" || process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true";
1092
+ }
1093
+ function initServerAnalytics(serverLogger) {
1094
+ logger = serverLogger;
1095
+ if (isTelemetryDisabled()) {
1096
+ logger.info("\u9065\u6D4B\u5DF2\u7981\u7528 (MG_TELEMETRY_DISABLED \u6216 DO_NOT_TRACK)");
1097
+ return;
1098
+ }
1099
+ if (!posthogClient) {
1100
+ posthogClient = new PostHog(POSTHOG_API_KEY, {
1101
+ host: POSTHOG_HOST,
1102
+ // Server 端使用批量模式,减少网络请求
1103
+ flushAt: 10,
1104
+ flushInterval: 3e4
1105
+ // 30 秒
1106
+ });
1107
+ logger.info("PostHog Analytics \u5DF2\u521D\u59CB\u5316");
1108
+ }
1109
+ }
1110
+ function trackEvent(eventData) {
1111
+ if (!posthogClient) {
1112
+ return;
1113
+ }
1114
+ try {
1115
+ posthogClient.capture({
1116
+ distinctId: eventData.distinctId,
1117
+ event: eventData.event,
1118
+ properties: eventData.properties
1119
+ });
1120
+ logger?.info(`\u7EDF\u8BA1\u4E8B\u4EF6\u5DF2\u8BB0\u5F55: ${eventData.event}`, eventData.properties);
1121
+ } catch (error) {
1122
+ logger?.error("\u7EDF\u8BA1\u4E8B\u4EF6\u8BB0\u5F55\u5931\u8D25:", error);
1123
+ }
1124
+ }
1125
+ async function shutdownServerAnalytics() {
1126
+ if (posthogClient) {
1127
+ try {
1128
+ logger?.info("\u6B63\u5728\u53D1\u9001\u5269\u4F59\u7EDF\u8BA1\u4E8B\u4EF6...");
1129
+ await posthogClient.shutdown();
1130
+ logger?.info("PostHog Analytics \u5DF2\u5173\u95ED");
1131
+ } catch (error) {
1132
+ logger?.error("\u5173\u95ED PostHog \u5931\u8D25:", error);
1133
+ }
1134
+ posthogClient = null;
1135
+ }
1136
+ }
1137
+
1025
1138
  // src/server/websocket-server.ts
1026
1139
  var MGServer = class {
1027
1140
  wss = null;
@@ -1053,6 +1166,7 @@ var MGServer = class {
1053
1166
  this.startedAt = /* @__PURE__ */ new Date();
1054
1167
  this.logger.info(`Server \u542F\u52A8\u6210\u529F\uFF0C\u76D1\u542C\u7AEF\u53E3: ${port}`);
1055
1168
  this.connectionManager.startHeartbeatCheck(HEARTBEAT_INTERVAL);
1169
+ initServerAnalytics(this.logger);
1056
1170
  resolve2(port);
1057
1171
  });
1058
1172
  this.wss.on("error", (error) => {
@@ -1112,6 +1226,10 @@ var MGServer = class {
1112
1226
  this.handleRegister(ws, message);
1113
1227
  return;
1114
1228
  }
1229
+ if (message.type === "track_analytics" /* TRACK_ANALYTICS */) {
1230
+ this.handleTrackAnalytics(message);
1231
+ return;
1232
+ }
1115
1233
  const managedWs = ws;
1116
1234
  if (!managedWs.connectionId) {
1117
1235
  this.logger.warn("\u672A\u6CE8\u518C\u7684\u8FDE\u63A5\u53D1\u9001\u6D88\u606F\uFF0C\u5FFD\u7565");
@@ -1189,6 +1307,9 @@ var MGServer = class {
1189
1307
  case "navigate_to_node" /* NAVIGATE_TO_NODE */:
1190
1308
  this.handleNavigateToNode(ws, message);
1191
1309
  break;
1310
+ case "track_analytics" /* TRACK_ANALYTICS */:
1311
+ this.handleTrackAnalytics(message);
1312
+ break;
1192
1313
  case "response" /* RESPONSE */:
1193
1314
  case "error" /* ERROR */:
1194
1315
  this.requestHandler.handleResponse(message);
@@ -1334,6 +1455,15 @@ var MGServer = class {
1334
1455
  }
1335
1456
  });
1336
1457
  }
1458
+ /**
1459
+ * 处理统计事件
1460
+ */
1461
+ handleTrackAnalytics(message) {
1462
+ const eventData = message.data;
1463
+ if (eventData) {
1464
+ trackEvent(eventData);
1465
+ }
1466
+ }
1337
1467
  /**
1338
1468
  * 处理节点导航请求
1339
1469
  */
@@ -1407,6 +1537,7 @@ var MGServer = class {
1407
1537
  return;
1408
1538
  }
1409
1539
  this.logger.info("\u6B63\u5728\u505C\u6B62 Server...");
1540
+ await shutdownServerAnalytics();
1410
1541
  this.requestHandler.cleanupAll();
1411
1542
  this.connectionManager.closeAll();
1412
1543
  return new Promise((resolve2) => {
@@ -1738,12 +1869,14 @@ export {
1738
1869
  formatLogTime,
1739
1870
  generateId,
1740
1871
  generateMgpLink,
1872
+ generateMultiNodeMgpLink,
1741
1873
  generatePageLink,
1742
1874
  getCurrentISOTime,
1743
1875
  isDesignPageUrl,
1744
1876
  isProcessRunning,
1745
1877
  killProcess,
1746
1878
  normalizePageUrl,
1879
+ normalizePageUrlWithPageId,
1747
1880
  parseMgpLink,
1748
1881
  readServerInfo,
1749
1882
  resolveOutputPath,