@xbrowser/cli 1.5.4 → 1.6.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.
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-WCM4FNUB.js";
24
- import "./chunk-74QM55TC.js";
23
+ } from "./chunk-6QGZN5U7.js";
24
+ import "./chunk-VJNMAWPZ.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-KFQGP6VL.js";
@@ -20,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-H7R352A2.js";
23
+ } from "./chunk-35DOHDTA.js";
24
24
  import "./chunk-TNEN6VQ2.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-MKEAO3XJ.js";
24
- import "./chunk-74QM55TC.js";
23
+ } from "./chunk-IGWWPMEQ.js";
24
+ import "./chunk-VJNMAWPZ.js";
25
25
  import "./chunk-TNEN6VQ2.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-ABXMBNQ6.js";
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-74QM55TC.js";
17
+ } from "./chunk-VJNMAWPZ.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -315,10 +315,23 @@ async function waitForActionable(page, selector, opts = {}) {
315
315
  if (!rect2) throw new Error(`Element not found: ${selector}`);
316
316
  return { nodeId: 0, rect: rect2 };
317
317
  }
318
- const nodeId = await page.querySelector(selector);
319
- if (!nodeId) throw new Error(`Element not found: ${selector}`);
320
- const rect = await page.getBoxModel(nodeId);
321
- if (!rect) throw new Error(`Element has no box: ${selector}`);
318
+ const deadline2 = Date.now() + timeout;
319
+ let lastError;
320
+ let nodeId = 0;
321
+ let rect = null;
322
+ while (Date.now() < deadline2) {
323
+ nodeId = await page.querySelector(selector);
324
+ if (!nodeId) {
325
+ lastError = `Element not found: ${selector}`;
326
+ await page.waitForTimeout(200);
327
+ continue;
328
+ }
329
+ rect = await page.getBoxModel(nodeId);
330
+ if (rect) break;
331
+ lastError = `Element has no box: ${selector}`;
332
+ await page.waitForTimeout(500);
333
+ }
334
+ if (!rect) throw new Error(lastError || `Element has no box: ${selector}`);
322
335
  return { nodeId, rect };
323
336
  }
324
337
  const deadline = Date.now() + timeout;
@@ -1165,6 +1178,15 @@ var XBPageImpl = class _XBPageImpl {
1165
1178
  if (result.errorText) {
1166
1179
  throw new Error(`Navigation failed: ${result.errorText}`);
1167
1180
  }
1181
+ if (waitUntil === "commit") {
1182
+ this._url = url;
1183
+ return {
1184
+ status: () => 0,
1185
+ ok: () => false,
1186
+ url: () => url,
1187
+ headers: () => ({})
1188
+ };
1189
+ }
1168
1190
  await this.waitForLoadState(waitUntil, timeout);
1169
1191
  this._url = url;
1170
1192
  const statusCode = 200;
@@ -320,10 +320,23 @@ async function waitForActionable(page, selector, opts = {}) {
320
320
  if (!rect2) throw new Error(`Element not found: ${selector}`);
321
321
  return { nodeId: 0, rect: rect2 };
322
322
  }
323
- const nodeId = await page.querySelector(selector);
324
- if (!nodeId) throw new Error(`Element not found: ${selector}`);
325
- const rect = await page.getBoxModel(nodeId);
326
- if (!rect) throw new Error(`Element has no box: ${selector}`);
323
+ const deadline2 = Date.now() + timeout;
324
+ let lastError;
325
+ let nodeId = 0;
326
+ let rect = null;
327
+ while (Date.now() < deadline2) {
328
+ nodeId = await page.querySelector(selector);
329
+ if (!nodeId) {
330
+ lastError = `Element not found: ${selector}`;
331
+ await page.waitForTimeout(200);
332
+ continue;
333
+ }
334
+ rect = await page.getBoxModel(nodeId);
335
+ if (rect) break;
336
+ lastError = `Element has no box: ${selector}`;
337
+ await page.waitForTimeout(500);
338
+ }
339
+ if (!rect) throw new Error(lastError || `Element has no box: ${selector}`);
327
340
  return { nodeId, rect };
328
341
  }
329
342
  const deadline = Date.now() + timeout;
@@ -1170,6 +1183,15 @@ var XBPageImpl = class _XBPageImpl {
1170
1183
  if (result.errorText) {
1171
1184
  throw new Error(`Navigation failed: ${result.errorText}`);
1172
1185
  }
1186
+ if (waitUntil === "commit") {
1187
+ this._url = url;
1188
+ return {
1189
+ status: () => 0,
1190
+ ok: () => false,
1191
+ url: () => url,
1192
+ headers: () => ({})
1193
+ };
1194
+ }
1173
1195
  await this.waitForLoadState(waitUntil, timeout);
1174
1196
  this._url = url;
1175
1197
  const statusCode = 200;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-74QM55TC.js";
3
+ } from "./chunk-VJNMAWPZ.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-74QM55TC.js";
3
+ } from "./chunk-VJNMAWPZ.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -314,10 +314,23 @@ async function waitForActionable(page, selector, opts = {}) {
314
314
  if (!rect2) throw new Error(`Element not found: ${selector}`);
315
315
  return { nodeId: 0, rect: rect2 };
316
316
  }
317
- const nodeId = await page.querySelector(selector);
318
- if (!nodeId) throw new Error(`Element not found: ${selector}`);
319
- const rect = await page.getBoxModel(nodeId);
320
- if (!rect) throw new Error(`Element has no box: ${selector}`);
317
+ const deadline2 = Date.now() + timeout;
318
+ let lastError;
319
+ let nodeId = 0;
320
+ let rect = null;
321
+ while (Date.now() < deadline2) {
322
+ nodeId = await page.querySelector(selector);
323
+ if (!nodeId) {
324
+ lastError = `Element not found: ${selector}`;
325
+ await page.waitForTimeout(200);
326
+ continue;
327
+ }
328
+ rect = await page.getBoxModel(nodeId);
329
+ if (rect) break;
330
+ lastError = `Element has no box: ${selector}`;
331
+ await page.waitForTimeout(500);
332
+ }
333
+ if (!rect) throw new Error(lastError || `Element has no box: ${selector}`);
321
334
  return { nodeId, rect };
322
335
  }
323
336
  const deadline = Date.now() + timeout;
@@ -1164,6 +1177,15 @@ var XBPageImpl = class _XBPageImpl {
1164
1177
  if (result.errorText) {
1165
1178
  throw new Error(`Navigation failed: ${result.errorText}`);
1166
1179
  }
1180
+ if (waitUntil === "commit") {
1181
+ this._url = url;
1182
+ return {
1183
+ status: () => 0,
1184
+ ok: () => false,
1185
+ url: () => url,
1186
+ headers: () => ({})
1187
+ };
1188
+ }
1167
1189
  await this.waitForLoadState(waitUntil, timeout);
1168
1190
  this._url = url;
1169
1191
  const statusCode = 200;
package/dist/cli.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  resolveLaunchOpts,
26
26
  saveSessionDiskMeta,
27
27
  setActivePage
28
- } from "./chunk-H7R352A2.js";
28
+ } from "./chunk-35DOHDTA.js";
29
29
  import "./chunk-TNEN6VQ2.js";
30
30
  import {
31
31
  forwardCommandLog,
@@ -337,7 +337,7 @@ var gotoCommand = registerCommand({
337
337
  scope: "page",
338
338
  parameters: z.object({
339
339
  url: z.string(),
340
- waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).optional(),
340
+ waitUntil: z.enum(["load", "domcontentloaded", "networkidle", "commit"]).optional(),
341
341
  timeout: z.number().optional()
342
342
  }),
343
343
  result: z.object({
@@ -7137,7 +7137,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7137
7137
  }
7138
7138
  let targetPageOverride = null;
7139
7139
  if (_target && extraOpts?.cdpEndpoint) {
7140
- const { findTargetPage } = await import("./browser-2FJ4OO4H.js");
7140
+ const { findTargetPage } = await import("./browser-KVTJQKBA.js");
7141
7141
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7142
7142
  if (!targetPageOverride) {
7143
7143
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -12557,6 +12557,11 @@ async function routeCommand(argvIn, stdinCommands) {
12557
12557
  await handleChainInput(argv[0], argv);
12558
12558
  return;
12559
12559
  }
12560
+ const jsonBeforeChain = (argv[0] === "--json" || argv[0] === "--yaml") && argv[1] && isChainInput(argv[1]);
12561
+ if (jsonBeforeChain) {
12562
+ await handleChainInput(argv[1], argv);
12563
+ return;
12564
+ }
12560
12565
  const globalFlags = /* @__PURE__ */ new Set(["--session", "--cdp", "--json", "--yaml", "--output", "--timeout", "--help", "-h", "--version"]);
12561
12566
  let chainArgIdx = -1;
12562
12567
  for (let i = 0; i < argv.length; i++) {
@@ -12581,11 +12586,13 @@ async function routeCommand(argvIn, stdinCommands) {
12581
12586
  outputError(e instanceof Error ? e.message : String(e));
12582
12587
  return;
12583
12588
  }
12589
+ const hasJsonFlag = argv.some((a) => a === "--json" || a.startsWith("--json="));
12590
+ const hasYamlFlag = argv.some((a) => a === "--yaml" || a.startsWith("--yaml="));
12584
12591
  const parsed = parseArgs(argv);
12585
12592
  const { positional, options } = parsed;
12586
12593
  const command = positional[0];
12587
12594
  const cmdArgs = positional.slice(1);
12588
- const mode = options.json ? "json" : options.yaml ? "yaml" : "text";
12595
+ const mode = options.json || hasJsonFlag ? "json" : options.yaml || hasYamlFlag ? "yaml" : "text";
12589
12596
  const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
12590
12597
  const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
12591
12598
  if (options.version || options.v && positional.length === 0) {
@@ -12593,8 +12600,13 @@ async function routeCommand(argvIn, stdinCommands) {
12593
12600
  return;
12594
12601
  }
12595
12602
  if (positional.length === 0) {
12596
- showMainHelp();
12597
- return;
12603
+ const chainHints = [options.json, options.yaml, options.session, options.cdp].filter(Boolean).find((v) => typeof v === "string" && v.includes(" "));
12604
+ if (chainHints) {
12605
+ positional.push(chainHints);
12606
+ } else {
12607
+ showMainHelp();
12608
+ return;
12609
+ }
12598
12610
  }
12599
12611
  if ((options.help || options.h) && positional.length > 0) {
12600
12612
  const loader = await getPluginLoader();
@@ -13210,7 +13222,7 @@ async function main() {
13210
13222
  const command = process.argv[2];
13211
13223
  const isLongRunning = command === "preview" || command === "serve";
13212
13224
  if (!isLongRunning) {
13213
- const { ensureProcessCanExit } = await import("./browser-2FJ4OO4H.js");
13225
+ const { ensureProcessCanExit } = await import("./browser-KVTJQKBA.js");
13214
13226
  await ensureProcessCanExit().catch(() => {
13215
13227
  });
13216
13228
  process.exit(exitCode);
@@ -21,8 +21,8 @@ import {
21
21
  resolveLaunchOpts,
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
- } from "./chunk-WCM4FNUB.js";
25
- import "./chunk-74QM55TC.js";
24
+ } from "./chunk-6QGZN5U7.js";
25
+ import "./chunk-VJNMAWPZ.js";
26
26
  import "./chunk-TNEN6VQ2.js";
27
27
  import {
28
28
  getPluginLoader
@@ -298,7 +298,7 @@ var gotoCommand = registerCommand({
298
298
  scope: "page",
299
299
  parameters: z.object({
300
300
  url: z.string(),
301
- waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).optional(),
301
+ waitUntil: z.enum(["load", "domcontentloaded", "networkidle", "commit"]).optional(),
302
302
  timeout: z.number().optional()
303
303
  }),
304
304
  result: z.object({
@@ -6668,7 +6668,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6668
6668
  }
6669
6669
  let targetPageOverride = null;
6670
6670
  if (_target && extraOpts?.cdpEndpoint) {
6671
- const { findTargetPage } = await import("./browser-IS6DTR5Y.js");
6671
+ const { findTargetPage } = await import("./browser-4PIVOYCW.js");
6672
6672
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6673
6673
  if (!targetPageOverride) {
6674
6674
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -8384,7 +8384,7 @@ function createRPCHandler() {
8384
8384
  const isNewFormat = Array.isArray(parsed.actions);
8385
8385
  if (isNewFormat) {
8386
8386
  try {
8387
- const { SessionReplayer } = await import("./session-replayer-SD2MWGP5.js");
8387
+ const { SessionReplayer } = await import("./session-replayer-RWFOWH3F.js");
8388
8388
  const replayer = new SessionReplayer({
8389
8389
  page: session.page,
8390
8390
  stepDelay: slowMo * 500,
package/dist/index.js CHANGED
@@ -81,8 +81,8 @@ import {
81
81
  resolveLaunchOpts,
82
82
  saveSessionDiskMeta,
83
83
  setActivePage
84
- } from "./chunk-MKEAO3XJ.js";
85
- import "./chunk-74QM55TC.js";
84
+ } from "./chunk-IGWWPMEQ.js";
85
+ import "./chunk-VJNMAWPZ.js";
86
86
  import "./chunk-TNEN6VQ2.js";
87
87
  import {
88
88
  errMsg
@@ -377,7 +377,7 @@ var gotoCommand = registerCommand({
377
377
  scope: "page",
378
378
  parameters: z.object({
379
379
  url: z.string(),
380
- waitUntil: z.enum(["load", "domcontentloaded", "networkidle"]).optional(),
380
+ waitUntil: z.enum(["load", "domcontentloaded", "networkidle", "commit"]).optional(),
381
381
  timeout: z.number().optional()
382
382
  }),
383
383
  result: z.object({
@@ -7457,7 +7457,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7457
7457
  }
7458
7458
  let targetPageOverride = null;
7459
7459
  if (_target && extraOpts?.cdpEndpoint) {
7460
- const { findTargetPage } = await import("./browser-ZFW2XADE.js");
7460
+ const { findTargetPage } = await import("./browser-RJIRI2H5.js");
7461
7461
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7462
7462
  if (!targetPageOverride) {
7463
7463
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -12880,6 +12880,11 @@ async function routeCommand(argvIn, stdinCommands) {
12880
12880
  await handleChainInput(argv[0], argv);
12881
12881
  return;
12882
12882
  }
12883
+ const jsonBeforeChain = (argv[0] === "--json" || argv[0] === "--yaml") && argv[1] && isChainInput(argv[1]);
12884
+ if (jsonBeforeChain) {
12885
+ await handleChainInput(argv[1], argv);
12886
+ return;
12887
+ }
12883
12888
  const globalFlags = /* @__PURE__ */ new Set(["--session", "--cdp", "--json", "--yaml", "--output", "--timeout", "--help", "-h", "--version"]);
12884
12889
  let chainArgIdx = -1;
12885
12890
  for (let i = 0; i < argv.length; i++) {
@@ -12904,11 +12909,13 @@ async function routeCommand(argvIn, stdinCommands) {
12904
12909
  outputError(e instanceof Error ? e.message : String(e));
12905
12910
  return;
12906
12911
  }
12912
+ const hasJsonFlag = argv.some((a) => a === "--json" || a.startsWith("--json="));
12913
+ const hasYamlFlag = argv.some((a) => a === "--yaml" || a.startsWith("--yaml="));
12907
12914
  const parsed = parseArgs(argv);
12908
12915
  const { positional, options } = parsed;
12909
12916
  const command = positional[0];
12910
12917
  const cmdArgs = positional.slice(1);
12911
- const mode = options.json ? "json" : options.yaml ? "yaml" : "text";
12918
+ const mode = options.json || hasJsonFlag ? "json" : options.yaml || hasYamlFlag ? "yaml" : "text";
12912
12919
  const sessionName = options.session || process.env.XBROWSER_SESSION || "default";
12913
12920
  const cdpEndpoint = options.cdp || process.env.XBROWSER_CDP;
12914
12921
  if (options.version || options.v && positional.length === 0) {
@@ -12916,8 +12923,13 @@ async function routeCommand(argvIn, stdinCommands) {
12916
12923
  return;
12917
12924
  }
12918
12925
  if (positional.length === 0) {
12919
- showMainHelp();
12920
- return;
12926
+ const chainHints = [options.json, options.yaml, options.session, options.cdp].filter(Boolean).find((v) => typeof v === "string" && v.includes(" "));
12927
+ if (chainHints) {
12928
+ positional.push(chainHints);
12929
+ } else {
12930
+ showMainHelp();
12931
+ return;
12932
+ }
12921
12933
  }
12922
12934
  if ((options.help || options.h) && positional.length > 0) {
12923
12935
  const loader = await getPluginLoader();
@@ -16320,7 +16332,7 @@ var DataCollector = class {
16320
16332
  return results;
16321
16333
  }
16322
16334
  async createBrowserContext() {
16323
- const { launch } = await import("./cdp-driver-QHTXQRQ2.js");
16335
+ const { launch } = await import("./cdp-driver-6EVYLHL2.js");
16324
16336
  const { browser } = await launch({
16325
16337
  headless: true,
16326
16338
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -31,7 +31,7 @@ var SessionReplayer = class {
31
31
  if (this.opts.page) {
32
32
  this.page = this.opts.page;
33
33
  } else if (this.opts.cdpUrl) {
34
- const { launch } = await import("./cdp-driver-QHTXQRQ2.js");
34
+ const { launch } = await import("./cdp-driver-6EVYLHL2.js");
35
35
  const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
36
36
  let contexts = browser.contexts();
37
37
  for (let i = 0; i < 10 && contexts.length === 0; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.5.4",
3
+ "version": "1.6.0",
4
4
  "description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
5
5
  "type": "module",
6
6
  "bin": {