@xbrowser/cli 1.23.0 → 1.24.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.
@@ -69,6 +69,35 @@ import {
69
69
  removeSession
70
70
  } from "@dyyz1993/xcli-core";
71
71
 
72
+ // src/fail-codes.ts
73
+ var FAIL_CODES = {
74
+ selectorNotFound: "RETRYABLE: selector-not-found",
75
+ pageNotReady: "RETRYABLE: page-not-ready",
76
+ elementGone: "RETRYABLE: element-gone",
77
+ captcha: "HUMAN: captcha",
78
+ loginWall: "HUMAN: login-wall",
79
+ permissionDenied: "FATAL: permission-denied",
80
+ targetGone: "FATAL: target-gone",
81
+ unknown: "FATAL: unknown"
82
+ };
83
+ function classifyFailure(message) {
84
+ const msg = (message || "").toLowerCase();
85
+ const pick = (code) => ({
86
+ code,
87
+ level: code.split(":")[0],
88
+ message: message || code
89
+ });
90
+ if (/captcha|验证码|人机校验|recaptcha|hcaptcha|turnstile/.test(msg)) return pick(FAIL_CODES.captcha);
91
+ if (/login|登录|signin|sign in|未登录|login-required|LOGIN_REQUIRED/.test(msg)) return pick(FAIL_CODES.loginWall);
92
+ if (/permission|权限|not allowed|forbidden|EACCES/.test(msg)) return pick(FAIL_CODES.permissionDenied);
93
+ if (/selector|选择器|element not found|未找到元素|no such element|queryselector returned null/.test(msg))
94
+ return pick(FAIL_CODES.selectorNotFound);
95
+ if (/timeout|超时|timed out|waiting for/.test(msg)) return pick(FAIL_CODES.pageNotReady);
96
+ if (/net::err|404|navigation failed|页面不存在|target closed|element-gone/.test(msg))
97
+ return pick(FAIL_CODES.targetGone);
98
+ return pick(FAIL_CODES.unknown);
99
+ }
100
+
72
101
  // src/executor.ts
73
102
  import {
74
103
  ok as ok30,
@@ -7966,7 +7995,16 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7966
7995
  if (isSuccess) {
7967
7996
  return { ...ok30(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
7968
7997
  }
7969
- return { success: false, data: raw.data, message: raw.message, tips: mergedOrRaw, duration, ...hookOutputs ? { hookOutputs } : {} };
7998
+ const fc = classifyFailure(raw.message);
7999
+ return {
8000
+ success: false,
8001
+ data: raw.data,
8002
+ message: raw.message,
8003
+ tips: mergedOrRaw,
8004
+ duration,
8005
+ error: { code: fc.code, level: fc.level },
8006
+ ...hookOutputs ? { hookOutputs } : {}
8007
+ };
7970
8008
  }
7971
8009
  const smartTipNormalized = normalizeTips6(smartTips);
7972
8010
  recordArchive(session?.id, sessionName, {
@@ -7985,7 +8023,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7985
8023
  const errorMessage = errMsg(err);
7986
8024
  if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
7987
8025
  try {
7988
- const { attemptRecovery } = await import("./recovery-LGY25LIM.js");
8026
+ const { attemptRecovery } = await import("./recovery-5C4FBA5O.js");
7989
8027
  const recovery = await attemptRecovery(
7990
8028
  session.page,
7991
8029
  sessionName,
@@ -8101,7 +8139,15 @@ async function executeChain(input, options) {
8101
8139
  continue;
8102
8140
  }
8103
8141
  const pluginArgs = cmdArgs.slice(1);
8104
- const pluginParams = parsePluginParams(pluginArgs, cmdEntry.parameters);
8142
+ let pluginParams = parsePluginParams(pluginArgs, cmdEntry.parameters);
8143
+ if (cmdEntry.parameters) {
8144
+ const schemaCheck = cmdEntry.parameters.safeParse(pluginParams);
8145
+ if (schemaCheck.success) {
8146
+ for (const [k, v] of Object.entries(schemaCheck.data)) {
8147
+ if (!(k in pluginParams)) pluginParams[k] = v;
8148
+ }
8149
+ }
8150
+ }
8105
8151
  const pluginCtx = {
8106
8152
  args: pluginArgs,
8107
8153
  options: pluginParams,
@@ -9025,7 +9071,7 @@ function createRPCHandler() {
9025
9071
  return result;
9026
9072
  } catch (err) {
9027
9073
  const errorMessage = errMsg(err);
9028
- const { attemptRecovery } = await import("./recovery-LGY25LIM.js");
9074
+ const { attemptRecovery } = await import("./recovery-5C4FBA5O.js");
9029
9075
  const recovery = await attemptRecovery(
9030
9076
  session?.page,
9031
9077
  sessionName,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HumanInteractionManager
3
- } from "./chunk-FBQZ3PVD.js";
3
+ } from "./chunk-PGKV24QN.js";
4
4
  import "./chunk-HBMEFSTB.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HumanInteractionManager
3
- } from "./chunk-LPW6QS4M.js";
3
+ } from "./chunk-SOPN4XDK.js";
4
4
  import "./chunk-ZTHE5RBZ.js";
5
5
  import "./chunk-KFQGP6VL.js";
6
6
  export {
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  HumanInteractionManager
3
- } from "./chunk-XTUAUFL3.js";
3
+ } from "./chunk-FNXA6FDM.js";
4
+ import "./chunk-ZTHE5RBZ.js";
4
5
  import "./chunk-KFQGP6VL.js";
5
6
  export {
6
7
  HumanInteractionManager
package/dist/index.d.ts CHANGED
@@ -836,6 +836,10 @@ interface ExecutionResult {
836
836
  duration: number;
837
837
  tips?: Tip[];
838
838
  hookOutputs?: HookOutput[];
839
+ error?: {
840
+ code: string;
841
+ level: string;
842
+ };
839
843
  }
840
844
  /**
841
845
  * Result of a single step within a command chain execution.
@@ -2488,6 +2492,10 @@ interface WebhookPayload {
2488
2492
  previewUrl?: string;
2489
2493
  targetUrl?: string;
2490
2494
  timeout?: number;
2495
+ /** Drel 等推送服务的通知标题(可选;缺省由 event 推导) */
2496
+ title?: string;
2497
+ /** Drel 等推送服务的通知正文(可选;缺省由其余字段拼装) */
2498
+ body?: string;
2491
2499
  }
2492
2500
  /**
2493
2501
  * Sends webhook notifications for browser automation lifecycle events.
@@ -2505,6 +2513,14 @@ declare class WebhookNotifier {
2505
2513
  * @returns `true` if the request succeeded (HTTP 2xx), `false` otherwise.
2506
2514
  */
2507
2515
  notify(payload: WebhookPayload): Promise<boolean>;
2516
+ /**
2517
+ * previewUrl 里的 localhost/127.0.0.1 替换为本机局域网 IPv4——
2518
+ * 推送目标是手机,localhost 在手机上不可达;同一 Wi-Fi 下局域网 IP 可达。
2519
+ */
2520
+ private lanify;
2521
+ /** Drel 推送端点识别(api.drel.app/<token>) */
2522
+ private isDrelEndpoint;
2523
+ private toDrelPayload;
2508
2524
  }
2509
2525
 
2510
2526
  interface CaptchaConfig {