@weapp-vite/miniprogram-automator 1.1.2 → 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.d.mts CHANGED
@@ -42,12 +42,15 @@ declare class Transport extends EventEmitter {
42
42
  }
43
43
  //#endregion
44
44
  //#region src/Connection.d.ts
45
+ interface SendOptions {
46
+ timeout?: number;
47
+ }
45
48
  /** Connection 的实现。 */
46
49
  declare class Connection extends EventEmitter {
47
50
  private transport;
48
51
  private callbacks;
49
52
  constructor(transport: Transport);
50
- send(method: string, params?: Record<string, any>): Promise<any>;
53
+ send(method: string, params?: Record<string, any>, options?: SendOptions): Promise<any>;
51
54
  dispose(): void;
52
55
  private onMessage;
53
56
  private onClose;
@@ -240,6 +243,10 @@ interface IToolClearCacheOptions {
240
243
  clean: 'all' | 'auth' | 'compile' | 'file' | 'network' | 'session' | 'storage';
241
244
  }
242
245
  type AutomatorCallable = (...args: any[]) => any;
246
+ interface CurrentPageOptions {
247
+ retries?: number;
248
+ timeout?: number;
249
+ }
243
250
  /** MiniProgram 的实现。 */
244
251
  declare class MiniProgram extends EventEmitter {
245
252
  private connection;
@@ -253,9 +260,10 @@ declare class MiniProgram extends EventEmitter {
253
260
  navigateBack(): Promise<any>;
254
261
  reLaunch(url: string): Promise<any>;
255
262
  switchTab(url: string): Promise<any>;
256
- currentPage(): Promise<Page>;
263
+ currentPage(options?: CurrentPageOptions): Promise<Page>;
257
264
  systemInfo(): Promise<any>;
258
265
  callWxMethod(method: string, ...args: any[]): Promise<any>;
266
+ private callWxMethodWithTimeout;
259
267
  mockWxMethod(method: string, result: any, ...args: any[]): Promise<void>;
260
268
  restoreWxMethod(method: string): Promise<void>;
261
269
  callPluginWxMethod(pluginId: string, method: string, ...args: any[]): Promise<any>;
@@ -293,6 +301,9 @@ declare class MiniProgram extends EventEmitter {
293
301
  refreshTicket(): Promise<void>;
294
302
  native(): Native;
295
303
  private changeRoute;
304
+ private resolveRouteContextPage;
305
+ private readRoutePollingCurrentPage;
306
+ private readRoutePollingPageStack;
296
307
  private send;
297
308
  private onLogAdded;
298
309
  private onBindingCalled;
package/dist/index.mjs CHANGED
@@ -512,22 +512,23 @@ var Connection = class Connection extends EventEmitter {
512
512
  transport.on("message", this.onMessage);
513
513
  transport.on("close", this.onClose);
514
514
  }
515
- send(method, params = {}) {
515
+ send(method, params = {}, options = {}) {
516
516
  const id = uuid();
517
517
  const payload = stringify({
518
518
  id,
519
519
  method,
520
520
  params
521
521
  });
522
+ const requestTimeout = options.timeout ?? REQUEST_TIMEOUT;
522
523
  debugProtocol(`${dateFormat("yyyy-mm-dd HH:MM:ss:l")} SEND ► ${payload}`);
523
524
  return new Promise((resolve, reject) => {
524
525
  const timeout = setTimeout(() => {
525
526
  this.callbacks.delete(id);
526
- const error = /* @__PURE__ */ new Error(`DevTools did not respond to protocol method ${method} within ${REQUEST_TIMEOUT}ms`);
527
+ const error = /* @__PURE__ */ new Error(`DevTools did not respond to protocol method ${method} within ${requestTimeout}ms`);
527
528
  error.code = "DEVTOOLS_PROTOCOL_TIMEOUT";
528
529
  error.method = method;
529
530
  reject(error);
530
- }, REQUEST_TIMEOUT);
531
+ }, requestTimeout);
531
532
  this.callbacks.set(id, {
532
533
  resolve,
533
534
  reject,
@@ -586,7 +587,7 @@ async function launchHeadlessAutomator(options) {
586
587
  }
587
588
  //#endregion
588
589
  //#region package.json
589
- var version = "1.1.2";
590
+ var version = "1.1.3";
590
591
  //#endregion
591
592
  //#region src/Native.ts
592
593
  /** Native 的实现。 */
@@ -779,6 +780,8 @@ function extractPluginId(p) {
779
780
  const CLOSE_STEP_TIMEOUT = 2e3;
780
781
  const CURRENT_PAGE_RETRIES = 3;
781
782
  const CURRENT_PAGE_RETRY_DELAY = 400;
783
+ const CHANGE_ROUTE_CONTEXT_TIMEOUT = 12e3;
784
+ const CHANGE_ROUTE_CALL_TIMEOUT = 12e3;
782
785
  const CHANGE_ROUTE_READY_TIMEOUT = 15e3;
783
786
  const CHANGE_ROUTE_POLL_DELAY = 500;
784
787
  const CHANGE_ROUTE_DEBUG_ENABLED = process.env.WEAPP_VITE_E2E_CHANGE_ROUTE_DEBUG === "1";
@@ -799,6 +802,9 @@ function withTimeout(task, timeoutMs) {
799
802
  });
800
803
  });
801
804
  }
805
+ function isOperationTimeoutError(error, timeoutMs) {
806
+ return error instanceof Error && error.message.includes(`Operation timed out after ${timeoutMs}ms`);
807
+ }
802
808
  function isFnStr(value) {
803
809
  if (!isStr(value)) return false;
804
810
  const trimmed = trim(value);
@@ -810,6 +816,12 @@ function isCurrentPageProtocolTimeout(error) {
810
816
  function isPageStackProtocolTimeout(error) {
811
817
  return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.getPageStack";
812
818
  }
819
+ function isCallWxMethodProtocolTimeout(error) {
820
+ return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callWxMethod";
821
+ }
822
+ function isRouteContextProbeError(error) {
823
+ return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error);
824
+ }
813
825
  function normalizeRoutePath(value) {
814
826
  return String(value ?? "").split("?", 1)[0].replace(/^\/+/, "").replace(/\/+$/, "");
815
827
  }
@@ -855,10 +867,12 @@ var MiniProgram = class extends EventEmitter {
855
867
  async switchTab(url) {
856
868
  return await this.changeRoute("switchTab", url);
857
869
  }
858
- async currentPage() {
870
+ async currentPage(options = {}) {
859
871
  let lastError;
860
- for (let attempt = 1; attempt <= CURRENT_PAGE_RETRIES; attempt += 1) try {
861
- const { pageId, path, query } = await this.send("App.getCurrentPage");
872
+ const retries = options.retries ?? CURRENT_PAGE_RETRIES;
873
+ const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
874
+ for (let attempt = 1; attempt <= retries; attempt += 1) try {
875
+ const { pageId, path, query } = await this.send("App.getCurrentPage", {}, sendOptions);
862
876
  return Page.create(this.connection, {
863
877
  id: pageId,
864
878
  path,
@@ -867,13 +881,13 @@ var MiniProgram = class extends EventEmitter {
867
881
  } catch (error) {
868
882
  lastError = error;
869
883
  if (!isCurrentPageProtocolTimeout(error)) throw error;
870
- if (attempt < CURRENT_PAGE_RETRIES) {
884
+ if (attempt < retries) {
871
885
  await sleep(CURRENT_PAGE_RETRY_DELAY);
872
886
  continue;
873
887
  }
874
888
  }
875
889
  if (isCurrentPageProtocolTimeout(lastError)) try {
876
- const { pageStack } = await this.send("App.getPageStack");
890
+ const { pageStack } = await this.send("App.getPageStack", {}, sendOptions);
877
891
  const page = pageStack[pageStack.length - 1];
878
892
  if (page) return Page.create(this.connection, {
879
893
  id: page.pageId,
@@ -894,6 +908,12 @@ var MiniProgram = class extends EventEmitter {
894
908
  args
895
909
  })).result;
896
910
  }
911
+ async callWxMethodWithTimeout(method, timeout, ...args) {
912
+ return (await this.send("App.callWxMethod", {
913
+ method,
914
+ args
915
+ }, { timeout })).result;
916
+ }
897
917
  async mockWxMethod(method, result, ...args) {
898
918
  if (isFn(result) || isFnStr(result)) {
899
919
  await this.send("App.mockWxMethod", {
@@ -1042,33 +1062,22 @@ var MiniProgram = class extends EventEmitter {
1042
1062
  return this.nativeIns;
1043
1063
  }
1044
1064
  async changeRoute(method, url) {
1045
- const currentPage = await this.currentPage().catch(async (error) => {
1046
- if (!isCurrentPageProtocolTimeout(error)) throw error;
1047
- try {
1048
- const { pageStack } = await this.send("App.getPageStack");
1049
- const page = pageStack[pageStack.length - 1];
1050
- return page ? Page.create(this.connection, {
1051
- id: page.pageId,
1052
- path: page.path,
1053
- query: page.query
1054
- }, this.pageMap) : void 0;
1055
- } catch (pageStackError) {
1056
- if (!isPageStackProtocolTimeout(pageStackError)) throw pageStackError;
1057
- return;
1058
- }
1059
- });
1065
+ const currentPage = await this.resolveRouteContextPage();
1060
1066
  logChangeRouteDebug(`start method=${method} url=${url ?? "<none>"} current=${currentPage?.path ?? "<none>"}`);
1061
- if (currentPage && isPluginPath(currentPage.path)) {
1062
- const pluginId = extractPluginId(currentPage.path);
1063
- await this.callPluginWxMethod(pluginId, method, { url });
1064
- } else await this.callWxMethod(method, { url });
1067
+ try {
1068
+ if (currentPage && isPluginPath(currentPage.path)) await this.callPluginWxMethod(extractPluginId(currentPage.path), method, { url });
1069
+ else await this.callWxMethodWithTimeout(method, CHANGE_ROUTE_CALL_TIMEOUT, { url });
1070
+ } catch (error) {
1071
+ if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT)) logChangeRouteDebug(`call-timeout method=${method} url=${url ?? "<none>"}`);
1072
+ else throw error;
1073
+ }
1065
1074
  const expectedRoute = normalizeRoutePath(url);
1066
1075
  const startedAt = Date.now();
1067
1076
  let lastPage;
1068
1077
  let lastError;
1069
1078
  while (Date.now() - startedAt <= CHANGE_ROUTE_READY_TIMEOUT) {
1070
1079
  try {
1071
- const page = await this.currentPage();
1080
+ const page = await this.readRoutePollingCurrentPage();
1072
1081
  lastPage = page;
1073
1082
  logChangeRouteDebug(`poll method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
1074
1083
  if (!expectedRoute || normalizeRoutePath(page?.path) === expectedRoute) {
@@ -1080,7 +1089,7 @@ var MiniProgram = class extends EventEmitter {
1080
1089
  logChangeRouteDebug(`poll-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
1081
1090
  }
1082
1091
  try {
1083
- const stack = await this.pageStack();
1092
+ const stack = await this.readRoutePollingPageStack();
1084
1093
  const stackTop = stack[stack.length - 1];
1085
1094
  if (stackTop) {
1086
1095
  lastPage = stackTop;
@@ -1093,6 +1102,10 @@ var MiniProgram = class extends EventEmitter {
1093
1102
  } catch (error) {
1094
1103
  lastError = error;
1095
1104
  logChangeRouteDebug(`stack-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
1105
+ if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT)) {
1106
+ await sleep(CHANGE_ROUTE_POLL_DELAY);
1107
+ continue;
1108
+ }
1096
1109
  }
1097
1110
  await sleep(CHANGE_ROUTE_POLL_DELAY);
1098
1111
  }
@@ -1103,8 +1116,38 @@ var MiniProgram = class extends EventEmitter {
1103
1116
  logChangeRouteDebug(`timeout method=${method} url=${url ?? "<none>"} current=<none> error=${lastError instanceof Error ? lastError.message : String(lastError)}`);
1104
1117
  throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}`);
1105
1118
  }
1106
- async send(method, params = {}) {
1107
- return await this.connection.send(method, params);
1119
+ async resolveRouteContextPage() {
1120
+ const currentPageTask = this.currentPage().catch((error) => {
1121
+ if (isRouteContextProbeError(error)) return;
1122
+ throw error;
1123
+ });
1124
+ const timeoutTask = sleep(CHANGE_ROUTE_CONTEXT_TIMEOUT).then(() => void 0);
1125
+ try {
1126
+ return await Promise.race([currentPageTask, timeoutTask]);
1127
+ } finally {
1128
+ currentPageTask.catch(() => {});
1129
+ }
1130
+ }
1131
+ async readRoutePollingCurrentPage() {
1132
+ const { pageId, path, query } = await this.send("App.getCurrentPage", {}, { timeout: CHANGE_ROUTE_CONTEXT_TIMEOUT });
1133
+ return Page.create(this.connection, {
1134
+ id: pageId,
1135
+ path,
1136
+ query
1137
+ }, this.pageMap);
1138
+ }
1139
+ async readRoutePollingPageStack() {
1140
+ const { pageStack } = await this.send("App.getPageStack", {}, { timeout: CHANGE_ROUTE_CONTEXT_TIMEOUT });
1141
+ return pageStack.map((page) => {
1142
+ return Page.create(this.connection, {
1143
+ id: page.pageId,
1144
+ path: page.path,
1145
+ query: page.query
1146
+ }, this.pageMap);
1147
+ });
1148
+ }
1149
+ async send(method, params = {}, options) {
1150
+ return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
1108
1151
  }
1109
1152
  onLogAdded = (payload) => {
1110
1153
  this.emit("console", payload);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weapp-vite/miniprogram-automator",
3
3
  "type": "module",
4
- "version": "1.1.2",
4
+ "version": "1.1.3",
5
5
  "description": "完全兼容微信 miniprogram-automator 的现代化替代实现",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "obug": "^2.1.1",
45
- "ws": "^8.20.1",
45
+ "ws": "^8.21.0",
46
46
  "@weapp-vite/qr": "1.1.0"
47
47
  },
48
48
  "publishConfig": {