@letsscrapedata/controller 0.2.0 → 0.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.
package/dist/index.cjs CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  LsdBrowserContextEvent: () => LsdBrowserContextEvent,
37
37
  LsdBrowserEvent: () => LsdBrowserEvent,
38
38
  LsdPageEvent: () => LsdPageEvent,
39
+ POPUP_TASK_ID: () => POPUP_TASK_ID,
39
40
  PlaywrightBrowser: () => PlaywrightBrowser,
40
41
  PlaywrightBrowserContext: () => PlaywrightBrowserContext,
41
42
  PlaywrightElement: () => PlaywrightElement,
@@ -74,6 +75,7 @@ var LsdBrowserEvent = /* @__PURE__ */ ((LsdBrowserEvent2) => {
74
75
  LsdBrowserEvent2["BROWSER_CONTEXT_CLOSE"] = "browserContextClose";
75
76
  return LsdBrowserEvent2;
76
77
  })(LsdBrowserEvent || {});
78
+ var POPUP_TASK_ID = 7;
77
79
 
78
80
  // src/utils/log.ts
79
81
  var import_utils = require("@letsscrapedata/utils");
@@ -430,6 +432,7 @@ var PlaywrightPage = class extends import_node_events.default {
430
432
  #lsdBrowserContext;
431
433
  #page;
432
434
  #status;
435
+ #lastStatusUpdateTime;
433
436
  #pageId;
434
437
  #closeWhenFree;
435
438
  #resquestInterceptionOptions;
@@ -672,12 +675,12 @@ var PlaywrightPage = class extends import_node_events.default {
672
675
  const pageInfo = p.pageInfo;
673
676
  let popupPageId = "page";
674
677
  if (pageInfo) {
675
- const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
678
+ const { taskId, browserIdx, browserContextIdx, pageIdx } = pageInfo;
676
679
  popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
677
680
  pageInfo.openType = "popup";
678
681
  evtData = this.browserContext().page(pageIdx);
679
- if (evtData && page.pageInfo?.taskId) {
680
- pageInfo.relatedId = page.pageInfo.taskId;
682
+ if (evtData) {
683
+ evtData.setPageInfo({ taskId: POPUP_TASK_ID, relatedId: taskId });
681
684
  }
682
685
  } else {
683
686
  logerr(`##browser page ${pageId} has popup without page.pageInfo @LsdPage`);
@@ -694,12 +697,13 @@ var PlaywrightPage = class extends import_node_events.default {
694
697
  throw new Error("Invalid paras in new LsdPage");
695
698
  }
696
699
  super();
700
+ const currentTime = (0, import_utils3.getCurrentUnixTime)();
697
701
  this.#lsdBrowserContext = browserContext;
698
702
  this.#page = page;
699
703
  this.#status = "free";
700
- const currentTime = (0, import_utils3.getCurrentUnixTime)();
701
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
702
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
704
+ this.#lastStatusUpdateTime = currentTime;
705
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
706
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
703
707
  this.#pageId = `PlaywrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
704
708
  this.#closeWhenFree = false;
705
709
  this.#resquestInterceptionOptions = [];
@@ -799,6 +803,7 @@ var PlaywrightPage = class extends import_node_events.default {
799
803
  await this.#page.close();
800
804
  this.#page = null;
801
805
  this.#status = "closed";
806
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
802
807
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
803
808
  return true;
804
809
  }
@@ -888,6 +893,7 @@ var PlaywrightPage = class extends import_node_events.default {
888
893
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
889
894
  }
890
895
  this.#status = "free";
896
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
891
897
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
892
898
  await this.clearRequestInterceptions();
893
899
  await this.clearResponseInterceptions();
@@ -923,8 +929,25 @@ var PlaywrightPage = class extends import_node_events.default {
923
929
  id() {
924
930
  return this.#pageId;
925
931
  }
926
- isFree() {
927
- return this.#status === "free";
932
+ isAvailable(domainName = "") {
933
+ if (domainName) {
934
+ return this.#status === "free" && this.url().includes(domainName);
935
+ } else if (this.#status !== "free") {
936
+ return false;
937
+ } else {
938
+ const url = this.url();
939
+ if (!url || url === "about:blank") {
940
+ return true;
941
+ }
942
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
943
+ if (maxReservedSeconds <= 0) {
944
+ return true;
945
+ }
946
+ return (0, import_utils3.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
947
+ }
948
+ }
949
+ lastStatusUpdateTime() {
950
+ return this.#lastStatusUpdateTime;
928
951
  }
929
952
  async localStroage() {
930
953
  if (!this.#page) {
@@ -1119,10 +1142,7 @@ var PlaywrightPage = class extends import_node_events.default {
1119
1142
  throw new Error("Invalid paras in setPageInfo");
1120
1143
  }
1121
1144
  const actPageInfo = this.#page.pageInfo;
1122
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
1123
- if (typeof lastStatusUpdateTime === "number") {
1124
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
1125
- }
1145
+ const { taskId, relatedId, misc } = pageInfo;
1126
1146
  if (typeof taskId === "number") {
1127
1147
  actPageInfo.taskId = taskId;
1128
1148
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -1353,6 +1373,7 @@ var PlaywrightPage = class extends import_node_events.default {
1353
1373
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
1354
1374
  }
1355
1375
  this.#status = "busy";
1376
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
1356
1377
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
1357
1378
  return true;
1358
1379
  }
@@ -1474,6 +1495,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1474
1495
  #browserContext;
1475
1496
  #browserContextCreationMethod;
1476
1497
  #userAgent;
1498
+ #maxReservedSeconds;
1477
1499
  #apiContext;
1478
1500
  #createTime;
1479
1501
  #lastStatusUpdateTime;
@@ -1492,9 +1514,8 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1492
1514
  }
1493
1515
  const pages = this.#browserContext.pages();
1494
1516
  const openType = this.#lsdBrowser.browserCreationMethod();
1495
- const lastStatusUpdateTime = (0, import_utils4.getCurrentUnixTime)();
1496
1517
  for (const page of pages) {
1497
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
1518
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
1498
1519
  const lsdPage = new PlaywrightPage(this, page, pageInfo);
1499
1520
  this.#lsdPages.push(lsdPage);
1500
1521
  if (this.#maxViewportOfNewPage) {
@@ -1509,7 +1530,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1509
1530
  }
1510
1531
  }
1511
1532
  }
1512
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
1533
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
1513
1534
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
1514
1535
  throw new Error(`Invalid lsdBrowser parameter`);
1515
1536
  }
@@ -1523,6 +1544,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1523
1544
  this.#browserContext = browserContext;
1524
1545
  this.#browserContextCreationMethod = browserContextCreationMethod;
1525
1546
  this.#userAgent = userAgent;
1547
+ this.#maxReservedSeconds = maxReservedSeconds;
1526
1548
  const apiRequestContext = browserContext.request;
1527
1549
  this.#apiContext = new PlaywrightApiContext(apiRequestContext);
1528
1550
  const currentTime = (0, import_utils4.getCurrentUnixTime)();
@@ -1546,7 +1568,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1546
1568
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
1547
1569
  } else {
1548
1570
  const currentTime2 = (0, import_utils4.getCurrentUnixTime)();
1549
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
1571
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
1550
1572
  const lsdPage = new PlaywrightPage(this, page, pageInfo2);
1551
1573
  this.#lsdPages.push(lsdPage);
1552
1574
  if (this.#maxViewportOfNewPage) {
@@ -1612,7 +1634,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1612
1634
  if (maxPageFreeSeconds <= 0) {
1613
1635
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
1614
1636
  }
1615
- if (maxPageFreeSeconds <= 0) {
1637
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
1616
1638
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
1617
1639
  return false;
1618
1640
  }
@@ -1622,7 +1644,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1622
1644
  }
1623
1645
  try {
1624
1646
  const maxUpdateTime = (0, import_utils4.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
1625
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
1647
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
1626
1648
  if (freePages.length === this.#lsdPages.length) {
1627
1649
  freePages = freePages.slice(1);
1628
1650
  }
@@ -1647,7 +1669,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1647
1669
  const { browserIncognitos: incognitos } = browserContextRequirements;
1648
1670
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
1649
1671
  }
1650
- async getPage(always = false) {
1672
+ async getPage(domainName = "", always = false) {
1651
1673
  if (!this.#browserContext) {
1652
1674
  throw new Error("Invalid browserContext");
1653
1675
  }
@@ -1656,7 +1678,10 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1656
1678
  return null;
1657
1679
  }
1658
1680
  try {
1659
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
1681
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
1682
+ if (!lsdPage && domainName) {
1683
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1684
+ }
1660
1685
  if (lsdPage) {
1661
1686
  lsdPage.use();
1662
1687
  this.#freeGettingLock();
@@ -1674,7 +1699,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1674
1699
  } else {
1675
1700
  pageInfo.openType = "newpage";
1676
1701
  }
1677
- lsdPage = this.#lsdPages.find((p) => p.isFree());
1702
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1678
1703
  if (lsdPage) {
1679
1704
  if (!this.#userAgent) {
1680
1705
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -1709,7 +1734,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1709
1734
  hasFreePage(pageNum = 1) {
1710
1735
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
1711
1736
  return true;
1712
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
1737
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
1713
1738
  return true;
1714
1739
  } else {
1715
1740
  return false;
@@ -1724,6 +1749,9 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1724
1749
  isIncognito() {
1725
1750
  return this.#incognito;
1726
1751
  }
1752
+ maxReservedSeconds() {
1753
+ return this.#maxReservedSeconds;
1754
+ }
1727
1755
  page(pageIdx) {
1728
1756
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
1729
1757
  return lsdPage ? lsdPage : null;
@@ -1835,7 +1863,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1835
1863
  throw new Error(`Invalid playwright browser parameter`);
1836
1864
  }
1837
1865
  super();
1838
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1866
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1839
1867
  this.#browser = browser;
1840
1868
  this.#browserIdx = browserIdx;
1841
1869
  this.#pid = pid;
@@ -1860,7 +1888,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1860
1888
  }
1861
1889
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
1862
1890
  for (const browserContext of browserContexts) {
1863
- const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
1891
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
1864
1892
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1865
1893
  }
1866
1894
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -1921,8 +1949,8 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1921
1949
  browserContextOptions.userAgent = userAgent;
1922
1950
  }
1923
1951
  const browserContext = await this.#browser.newContext(browserContextOptions);
1924
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
1925
- const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
1952
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
1953
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
1926
1954
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1927
1955
  return lsdBrowserContext;
1928
1956
  }
@@ -2304,6 +2332,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2304
2332
  #lsdBrowserContext;
2305
2333
  #page;
2306
2334
  #status;
2335
+ #lastStatusUpdateTime;
2307
2336
  #pageId;
2308
2337
  #userAgent;
2309
2338
  #closeWhenFree;
@@ -2510,12 +2539,12 @@ var PuppeteerPage = class extends import_node_events4.default {
2510
2539
  const pageInfo = p.pageInfo;
2511
2540
  let popupPageId = "page";
2512
2541
  if (pageInfo) {
2513
- const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
2542
+ const { taskId, browserIdx, browserContextIdx, pageIdx } = pageInfo;
2514
2543
  popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
2515
2544
  pageInfo.openType = "popup";
2516
2545
  evtData = this.browserContext().page(pageIdx);
2517
- if (evtData && page.pageInfo?.taskId) {
2518
- pageInfo.relatedId = page.pageInfo.taskId;
2546
+ if (evtData) {
2547
+ evtData.setPageInfo({ taskId: POPUP_TASK_ID, relatedId: taskId });
2519
2548
  }
2520
2549
  } else {
2521
2550
  logerr(`##browser page ${pageId} has popup without page.pageInfo @LsdPage`);
@@ -2532,12 +2561,13 @@ var PuppeteerPage = class extends import_node_events4.default {
2532
2561
  throw new Error("Invalid paras in new LsdPage");
2533
2562
  }
2534
2563
  super();
2564
+ const currentTime = (0, import_utils7.getCurrentUnixTime)();
2535
2565
  this.#lsdBrowserContext = browserContext;
2536
2566
  this.#page = page;
2537
2567
  this.#status = "free";
2538
- const currentTime = (0, import_utils7.getCurrentUnixTime)();
2539
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
2540
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
2568
+ this.#lastStatusUpdateTime = currentTime;
2569
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
2570
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
2541
2571
  this.#pageId = `PuppeteerPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
2542
2572
  this.#userAgent = browserContext.userAgent();
2543
2573
  this.#closeWhenFree = false;
@@ -2634,6 +2664,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2634
2664
  await this.#page.close();
2635
2665
  this.#page = null;
2636
2666
  this.#status = "closed";
2667
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
2637
2668
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
2638
2669
  return true;
2639
2670
  }
@@ -2723,6 +2754,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2723
2754
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
2724
2755
  }
2725
2756
  this.#status = "free";
2757
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
2726
2758
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
2727
2759
  await this.clearRequestInterceptions();
2728
2760
  await this.clearResponseInterceptions();
@@ -2762,8 +2794,25 @@ var PuppeteerPage = class extends import_node_events4.default {
2762
2794
  id() {
2763
2795
  return this.#pageId;
2764
2796
  }
2765
- isFree() {
2766
- return this.#status === "free";
2797
+ isAvailable(domainName = "") {
2798
+ if (domainName) {
2799
+ return this.#status === "free" && this.url().includes(domainName);
2800
+ } else if (this.#status !== "free") {
2801
+ return false;
2802
+ } else {
2803
+ const url = this.url();
2804
+ if (!url || url === "about:blank") {
2805
+ return true;
2806
+ }
2807
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
2808
+ if (maxReservedSeconds <= 0) {
2809
+ return true;
2810
+ }
2811
+ return (0, import_utils7.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
2812
+ }
2813
+ }
2814
+ lastStatusUpdateTime() {
2815
+ return this.#lastStatusUpdateTime;
2767
2816
  }
2768
2817
  async localStroage() {
2769
2818
  if (!this.#page) {
@@ -2957,10 +3006,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2957
3006
  throw new Error("Invalid paras in setPageInfo");
2958
3007
  }
2959
3008
  const actPageInfo = this.#page.pageInfo;
2960
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
2961
- if (typeof lastStatusUpdateTime === "number") {
2962
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
2963
- }
3009
+ const { taskId, relatedId, misc } = pageInfo;
2964
3010
  if (typeof taskId === "number") {
2965
3011
  actPageInfo.taskId = taskId;
2966
3012
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -3178,6 +3224,7 @@ var PuppeteerPage = class extends import_node_events4.default {
3178
3224
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
3179
3225
  }
3180
3226
  this.#status = "busy";
3227
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
3181
3228
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
3182
3229
  return true;
3183
3230
  }
@@ -3271,6 +3318,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3271
3318
  */
3272
3319
  #bcUserAgent;
3273
3320
  #userAgent;
3321
+ #maxReservedSeconds;
3274
3322
  #createTime;
3275
3323
  #lastStatusUpdateTime;
3276
3324
  #status;
@@ -3288,9 +3336,8 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3288
3336
  }
3289
3337
  const pages = await this.#browserContext.pages();
3290
3338
  const openType = this.#lsdBrowser.browserCreationMethod();
3291
- const lastStatusUpdateTime = (0, import_utils8.getCurrentUnixTime)();
3292
3339
  for (const page of pages) {
3293
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
3340
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
3294
3341
  const lsdPage = new PuppeteerPage(this, page, pageInfo);
3295
3342
  this.#lsdPages.push(lsdPage);
3296
3343
  if (this.#maxViewportOfNewPage) {
@@ -3308,7 +3355,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3308
3355
  }
3309
3356
  }
3310
3357
  }
3311
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
3358
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
3312
3359
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
3313
3360
  throw new Error(`Invalid lsdBrowser parameter`);
3314
3361
  }
@@ -3323,6 +3370,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3323
3370
  this.#browserContextCreationMethod = browserContextCreationMethod;
3324
3371
  this.#bcUserAgent = userAgent;
3325
3372
  this.#userAgent = userAgent;
3373
+ this.#maxReservedSeconds = maxReservedSeconds;
3326
3374
  const currentTime = (0, import_utils8.getCurrentUnixTime)();
3327
3375
  this.#createTime = currentTime;
3328
3376
  this.#lastStatusUpdateTime = currentTime;
@@ -3349,7 +3397,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3349
3397
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
3350
3398
  } else {
3351
3399
  const currentTime2 = (0, import_utils8.getCurrentUnixTime)();
3352
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
3400
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
3353
3401
  const lsdPage = new PuppeteerPage(this, page, pageInfo2);
3354
3402
  this.#lsdPages.push(lsdPage);
3355
3403
  if (this.#maxViewportOfNewPage) {
@@ -3422,7 +3470,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3422
3470
  if (maxPageFreeSeconds <= 0) {
3423
3471
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
3424
3472
  }
3425
- if (maxPageFreeSeconds <= 0) {
3473
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
3426
3474
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
3427
3475
  return false;
3428
3476
  }
@@ -3432,7 +3480,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3432
3480
  }
3433
3481
  try {
3434
3482
  const maxUpdateTime = (0, import_utils8.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
3435
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
3483
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
3436
3484
  if (freePages.length === this.#lsdPages.length) {
3437
3485
  freePages = freePages.slice(1);
3438
3486
  }
@@ -3457,7 +3505,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3457
3505
  const { browserIncognitos: incognitos } = browserContextRequirements;
3458
3506
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
3459
3507
  }
3460
- async getPage(always = false) {
3508
+ async getPage(domainName = "", always = false) {
3461
3509
  if (!this.#browserContext) {
3462
3510
  throw new Error("Invalid browserContext");
3463
3511
  }
@@ -3469,7 +3517,10 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3469
3517
  if (this.#lsdPages.length === 0) {
3470
3518
  await (0, import_utils8.sleep)(1e3);
3471
3519
  }
3472
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
3520
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
3521
+ if (!lsdPage && domainName) {
3522
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3523
+ }
3473
3524
  if (lsdPage) {
3474
3525
  lsdPage.use();
3475
3526
  this.#freeGettingLock();
@@ -3489,7 +3540,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3489
3540
  } else {
3490
3541
  pageInfo.openType = "newpage";
3491
3542
  }
3492
- lsdPage = this.#lsdPages.find((p) => p.isFree());
3543
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3493
3544
  if (lsdPage) {
3494
3545
  if (!this.#userAgent) {
3495
3546
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -3524,7 +3575,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3524
3575
  hasFreePage(pageNum = 1) {
3525
3576
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
3526
3577
  return true;
3527
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
3578
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
3528
3579
  return true;
3529
3580
  } else {
3530
3581
  return false;
@@ -3539,6 +3590,9 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3539
3590
  isFree() {
3540
3591
  return this.#status === "free";
3541
3592
  }
3593
+ maxReservedSeconds() {
3594
+ return this.#maxReservedSeconds;
3595
+ }
3542
3596
  page(pageIdx) {
3543
3597
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
3544
3598
  return lsdPage ? lsdPage : null;
@@ -3653,7 +3707,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3653
3707
  throw new Error(`Invalid puppeteer browser parameter`);
3654
3708
  }
3655
3709
  super();
3656
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3710
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3657
3711
  this.#browser = browser;
3658
3712
  this.#browserIdx = browserIdx;
3659
3713
  this.#pid = pid;
@@ -3675,7 +3729,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3675
3729
  const browserContexts = browser.browserContexts();
3676
3730
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : false;
3677
3731
  for (const browserContext of browserContexts) {
3678
- const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), this.#userAgent(), maxViewportOfNewPage);
3732
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), this.#userAgent(), maxReservedSeconds, maxViewportOfNewPage);
3679
3733
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3680
3734
  }
3681
3735
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -3729,8 +3783,8 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3729
3783
  userAgent = lsdLaunchOptions.headlessUserAgent;
3730
3784
  }
3731
3785
  const browserContext = await this.#browser.createBrowserContext(browserContextOptions);
3732
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
3733
- const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
3786
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
3787
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
3734
3788
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3735
3789
  return lsdBrowserContext;
3736
3790
  }
@@ -4061,7 +4115,10 @@ var CheerioPage = class extends import_node_events7.default {
4061
4115
  id() {
4062
4116
  throw new Error("Not supported in CheerioPage.");
4063
4117
  }
4064
- isFree() {
4118
+ isAvailable() {
4119
+ throw new Error("Not supported in CheerioPage.");
4120
+ }
4121
+ lastStatusUpdateTime() {
4065
4122
  throw new Error("Not supported in CheerioPage.");
4066
4123
  }
4067
4124
  load(html, isHtml = true) {
@@ -4494,6 +4551,7 @@ var PatchrightPage = class extends import_node_events8.default {
4494
4551
  #lsdBrowserContext;
4495
4552
  #page;
4496
4553
  #status;
4554
+ #lastStatusUpdateTime;
4497
4555
  #pageId;
4498
4556
  #closeWhenFree;
4499
4557
  #resquestInterceptionOptions;
@@ -4736,12 +4794,12 @@ var PatchrightPage = class extends import_node_events8.default {
4736
4794
  const pageInfo = p.pageInfo;
4737
4795
  let popupPageId = "page";
4738
4796
  if (pageInfo) {
4739
- const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
4797
+ const { taskId, browserIdx, browserContextIdx, pageIdx } = pageInfo;
4740
4798
  popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
4741
4799
  pageInfo.openType = "popup";
4742
4800
  evtData = this.browserContext().page(pageIdx);
4743
- if (evtData && page.pageInfo?.taskId) {
4744
- pageInfo.relatedId = page.pageInfo.taskId;
4801
+ if (evtData) {
4802
+ evtData.setPageInfo({ taskId: POPUP_TASK_ID, relatedId: taskId });
4745
4803
  }
4746
4804
  } else {
4747
4805
  logerr(`##browser page ${pageId} has popup without page.pageInfo @LsdPage`);
@@ -4758,12 +4816,13 @@ var PatchrightPage = class extends import_node_events8.default {
4758
4816
  throw new Error("Invalid paras in new LsdPage");
4759
4817
  }
4760
4818
  super();
4819
+ const currentTime = (0, import_utils11.getCurrentUnixTime)();
4761
4820
  this.#lsdBrowserContext = browserContext;
4762
4821
  this.#page = page;
4763
4822
  this.#status = "free";
4764
- const currentTime = (0, import_utils11.getCurrentUnixTime)();
4765
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
4766
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
4823
+ this.#lastStatusUpdateTime = currentTime;
4824
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
4825
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
4767
4826
  this.#pageId = `PatchrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
4768
4827
  this.#closeWhenFree = false;
4769
4828
  this.#resquestInterceptionOptions = [];
@@ -4863,6 +4922,7 @@ var PatchrightPage = class extends import_node_events8.default {
4863
4922
  await this.#page.close();
4864
4923
  this.#page = null;
4865
4924
  this.#status = "closed";
4925
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
4866
4926
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
4867
4927
  return true;
4868
4928
  }
@@ -4951,6 +5011,7 @@ var PatchrightPage = class extends import_node_events8.default {
4951
5011
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
4952
5012
  }
4953
5013
  this.#status = "free";
5014
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
4954
5015
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
4955
5016
  await this.clearRequestInterceptions();
4956
5017
  await this.clearResponseInterceptions();
@@ -4986,8 +5047,25 @@ var PatchrightPage = class extends import_node_events8.default {
4986
5047
  id() {
4987
5048
  return this.#pageId;
4988
5049
  }
4989
- isFree() {
4990
- return this.#status === "free";
5050
+ isAvailable(domainName = "") {
5051
+ if (domainName) {
5052
+ return this.#status === "free" && this.url().includes(domainName);
5053
+ } else if (this.#status !== "free") {
5054
+ return false;
5055
+ } else {
5056
+ const url = this.url();
5057
+ if (!url || url === "about:blank") {
5058
+ return true;
5059
+ }
5060
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
5061
+ if (maxReservedSeconds <= 0) {
5062
+ return true;
5063
+ }
5064
+ return (0, import_utils11.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
5065
+ }
5066
+ }
5067
+ lastStatusUpdateTime() {
5068
+ return this.#lastStatusUpdateTime;
4991
5069
  }
4992
5070
  async localStroage() {
4993
5071
  if (!this.#page) {
@@ -5182,10 +5260,7 @@ var PatchrightPage = class extends import_node_events8.default {
5182
5260
  throw new Error("Invalid paras in setPageInfo");
5183
5261
  }
5184
5262
  const actPageInfo = this.#page.pageInfo;
5185
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
5186
- if (typeof lastStatusUpdateTime === "number") {
5187
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
5188
- }
5263
+ const { taskId, relatedId, misc } = pageInfo;
5189
5264
  if (typeof taskId === "number") {
5190
5265
  actPageInfo.taskId = taskId;
5191
5266
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -5416,6 +5491,7 @@ var PatchrightPage = class extends import_node_events8.default {
5416
5491
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
5417
5492
  }
5418
5493
  this.#status = "busy";
5494
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
5419
5495
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
5420
5496
  return true;
5421
5497
  }
@@ -5538,10 +5614,11 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5538
5614
  #browserContext;
5539
5615
  #browserContextCreationMethod;
5540
5616
  #userAgent;
5617
+ #maxReservedSeconds;
5541
5618
  #apiContext;
5542
5619
  #createTime;
5543
- #lastStatusUpdateTime;
5544
5620
  #status;
5621
+ #lastStatusUpdateTime;
5545
5622
  #incognito;
5546
5623
  #proxy;
5547
5624
  #maxPagesPerBrowserContext;
@@ -5556,9 +5633,8 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5556
5633
  }
5557
5634
  const pages = this.#browserContext.pages();
5558
5635
  const openType = this.#lsdBrowser.browserCreationMethod();
5559
- const lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
5560
5636
  for (const page of pages) {
5561
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
5637
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
5562
5638
  const lsdPage = new PatchrightPage(this, page, pageInfo);
5563
5639
  this.#lsdPages.push(lsdPage);
5564
5640
  if (this.#maxViewportOfNewPage) {
@@ -5573,7 +5649,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5573
5649
  }
5574
5650
  }
5575
5651
  }
5576
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
5652
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
5577
5653
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
5578
5654
  throw new Error(`Invalid lsdBrowser parameter`);
5579
5655
  }
@@ -5587,12 +5663,13 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5587
5663
  this.#browserContext = browserContext;
5588
5664
  this.#browserContextCreationMethod = browserContextCreationMethod;
5589
5665
  this.#userAgent = userAgent;
5666
+ this.#maxReservedSeconds = maxReservedSeconds;
5590
5667
  const apiRequestContext = browserContext.request;
5591
5668
  this.#apiContext = new PatchrightApiContext(apiRequestContext);
5592
5669
  const currentTime = (0, import_utils12.getCurrentUnixTime)();
5593
5670
  this.#createTime = currentTime;
5594
- this.#lastStatusUpdateTime = currentTime;
5595
5671
  this.#status = "free";
5672
+ this.#lastStatusUpdateTime = currentTime;
5596
5673
  this.#incognito = incognito === false ? false : true;
5597
5674
  this.#proxy = proxy?.proxyUrl ? proxy : null;
5598
5675
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -5610,7 +5687,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5610
5687
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
5611
5688
  } else {
5612
5689
  const currentTime2 = (0, import_utils12.getCurrentUnixTime)();
5613
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
5690
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
5614
5691
  const lsdPage = new PatchrightPage(this, page, pageInfo2);
5615
5692
  this.#lsdPages.push(lsdPage);
5616
5693
  if (this.#maxViewportOfNewPage) {
@@ -5676,7 +5753,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5676
5753
  if (maxPageFreeSeconds <= 0) {
5677
5754
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
5678
5755
  }
5679
- if (maxPageFreeSeconds <= 0) {
5756
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
5680
5757
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
5681
5758
  return false;
5682
5759
  }
@@ -5686,7 +5763,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5686
5763
  }
5687
5764
  try {
5688
5765
  const maxUpdateTime = (0, import_utils12.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
5689
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
5766
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
5690
5767
  if (freePages.length === this.#lsdPages.length) {
5691
5768
  freePages = freePages.slice(1);
5692
5769
  }
@@ -5711,7 +5788,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5711
5788
  const { browserIncognitos: incognitos } = browserContextRequirements;
5712
5789
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
5713
5790
  }
5714
- async getPage(always = false) {
5791
+ async getPage(domainName = "", always = false) {
5715
5792
  if (!this.#browserContext) {
5716
5793
  throw new Error("Invalid browserContext");
5717
5794
  }
@@ -5720,7 +5797,10 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5720
5797
  return null;
5721
5798
  }
5722
5799
  try {
5723
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
5800
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
5801
+ if (!lsdPage && domainName) {
5802
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5803
+ }
5724
5804
  if (lsdPage) {
5725
5805
  lsdPage.use();
5726
5806
  this.#freeGettingLock();
@@ -5738,7 +5818,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5738
5818
  } else {
5739
5819
  pageInfo.openType = "newpage";
5740
5820
  }
5741
- lsdPage = this.#lsdPages.find((p) => p.isFree());
5821
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5742
5822
  if (lsdPage) {
5743
5823
  if (!this.#userAgent) {
5744
5824
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -5773,7 +5853,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5773
5853
  hasFreePage(pageNum = 1) {
5774
5854
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
5775
5855
  return true;
5776
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
5856
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
5777
5857
  return true;
5778
5858
  } else {
5779
5859
  return false;
@@ -5788,6 +5868,9 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5788
5868
  isIncognito() {
5789
5869
  return this.#incognito;
5790
5870
  }
5871
+ maxReservedSeconds() {
5872
+ return this.#maxReservedSeconds;
5873
+ }
5791
5874
  page(pageIdx) {
5792
5875
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
5793
5876
  return lsdPage ? lsdPage : null;
@@ -5899,7 +5982,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5899
5982
  throw new Error(`Invalid playwright browser parameter`);
5900
5983
  }
5901
5984
  super();
5902
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5985
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5903
5986
  this.#browser = browser;
5904
5987
  this.#browserIdx = browserIdx;
5905
5988
  this.#pid = pid;
@@ -5924,7 +6007,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5924
6007
  }
5925
6008
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
5926
6009
  for (const browserContext of browserContexts) {
5927
- const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
6010
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
5928
6011
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5929
6012
  }
5930
6013
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -5985,8 +6068,8 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5985
6068
  browserContextOptions.userAgent = userAgent;
5986
6069
  }
5987
6070
  const browserContext = await this.#browser.newContext(browserContextOptions);
5988
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
5989
- const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
6071
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
6072
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
5990
6073
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5991
6074
  return lsdBrowserContext;
5992
6075
  }
@@ -6374,6 +6457,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6374
6457
  #lsdBrowserContext;
6375
6458
  #page;
6376
6459
  #status;
6460
+ #lastStatusUpdateTime;
6377
6461
  #pageId;
6378
6462
  #closeWhenFree;
6379
6463
  #resquestInterceptionOptions;
@@ -6616,12 +6700,12 @@ var CamoufoxPage = class extends import_node_events11.default {
6616
6700
  const pageInfo = p.pageInfo;
6617
6701
  let popupPageId = "page";
6618
6702
  if (pageInfo) {
6619
- const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
6703
+ const { taskId, browserIdx, browserContextIdx, pageIdx } = pageInfo;
6620
6704
  popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
6621
6705
  pageInfo.openType = "popup";
6622
6706
  evtData = this.browserContext().page(pageIdx);
6623
- if (evtData && page.pageInfo?.taskId) {
6624
- pageInfo.relatedId = page.pageInfo.taskId;
6707
+ if (evtData) {
6708
+ evtData.setPageInfo({ taskId: POPUP_TASK_ID, relatedId: taskId });
6625
6709
  }
6626
6710
  } else {
6627
6711
  logerr(`##browser page ${pageId} has popup without page.pageInfo @LsdPage`);
@@ -6638,12 +6722,13 @@ var CamoufoxPage = class extends import_node_events11.default {
6638
6722
  throw new Error("Invalid paras in new LsdPage");
6639
6723
  }
6640
6724
  super();
6725
+ const currentTime = (0, import_utils15.getCurrentUnixTime)();
6641
6726
  this.#lsdBrowserContext = browserContext;
6642
6727
  this.#page = page;
6643
6728
  this.#status = "free";
6644
- const currentTime = (0, import_utils15.getCurrentUnixTime)();
6645
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
6646
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
6729
+ this.#lastStatusUpdateTime = currentTime;
6730
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
6731
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
6647
6732
  this.#pageId = `CamoufoxPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
6648
6733
  this.#closeWhenFree = false;
6649
6734
  this.#resquestInterceptionOptions = [];
@@ -6729,6 +6814,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6729
6814
  await this.#page.close();
6730
6815
  this.#page = null;
6731
6816
  this.#status = "closed";
6817
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
6732
6818
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
6733
6819
  return true;
6734
6820
  }
@@ -6818,6 +6904,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6818
6904
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
6819
6905
  }
6820
6906
  this.#status = "free";
6907
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
6821
6908
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
6822
6909
  await this.clearRequestInterceptions();
6823
6910
  await this.clearResponseInterceptions();
@@ -6853,8 +6940,25 @@ var CamoufoxPage = class extends import_node_events11.default {
6853
6940
  id() {
6854
6941
  return this.#pageId;
6855
6942
  }
6856
- isFree() {
6857
- return this.#status === "free";
6943
+ isAvailable(domainName = "") {
6944
+ if (domainName) {
6945
+ return this.#status === "free" && this.url().includes(domainName);
6946
+ } else if (this.#status !== "free") {
6947
+ return false;
6948
+ } else {
6949
+ const url = this.url();
6950
+ if (!url || url === "about:blank") {
6951
+ return true;
6952
+ }
6953
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
6954
+ if (maxReservedSeconds <= 0) {
6955
+ return true;
6956
+ }
6957
+ return (0, import_utils15.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
6958
+ }
6959
+ }
6960
+ lastStatusUpdateTime() {
6961
+ return this.#lastStatusUpdateTime;
6858
6962
  }
6859
6963
  async localStroage() {
6860
6964
  if (!this.#page) {
@@ -7034,10 +7138,7 @@ var CamoufoxPage = class extends import_node_events11.default {
7034
7138
  throw new Error("Invalid paras in setPageInfo");
7035
7139
  }
7036
7140
  const actPageInfo = this.#page.pageInfo;
7037
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
7038
- if (typeof lastStatusUpdateTime === "number") {
7039
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
7040
- }
7141
+ const { taskId, relatedId, misc } = pageInfo;
7041
7142
  if (typeof taskId === "number") {
7042
7143
  actPageInfo.taskId = taskId;
7043
7144
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -7268,6 +7369,7 @@ var CamoufoxPage = class extends import_node_events11.default {
7268
7369
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
7269
7370
  }
7270
7371
  this.#status = "busy";
7372
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
7271
7373
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
7272
7374
  return true;
7273
7375
  }
@@ -7389,10 +7491,11 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7389
7491
  #browserContext;
7390
7492
  #browserContextCreationMethod;
7391
7493
  #userAgent;
7494
+ #maxReservedSeconds;
7392
7495
  #apiContext;
7393
7496
  #createTime;
7394
- #lastStatusUpdateTime;
7395
7497
  #status;
7498
+ #lastStatusUpdateTime;
7396
7499
  #incognito;
7397
7500
  #proxy;
7398
7501
  #maxPagesPerBrowserContext;
@@ -7407,9 +7510,8 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7407
7510
  }
7408
7511
  const pages = this.#browserContext.pages();
7409
7512
  const openType = this.#lsdBrowser.browserCreationMethod();
7410
- const lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
7411
7513
  for (const page of pages) {
7412
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
7514
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
7413
7515
  const lsdPage = new CamoufoxPage(this, page, pageInfo);
7414
7516
  this.#lsdPages.push(lsdPage);
7415
7517
  if (this.#maxViewportOfNewPage) {
@@ -7424,7 +7526,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7424
7526
  }
7425
7527
  }
7426
7528
  }
7427
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
7529
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
7428
7530
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
7429
7531
  throw new Error(`Invalid lsdBrowser parameter`);
7430
7532
  }
@@ -7438,12 +7540,13 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7438
7540
  this.#browserContext = browserContext;
7439
7541
  this.#browserContextCreationMethod = browserContextCreationMethod;
7440
7542
  this.#userAgent = userAgent;
7543
+ this.#maxReservedSeconds = maxReservedSeconds;
7441
7544
  const apiRequestContext = browserContext.request;
7442
7545
  this.#apiContext = new CamoufoxApiContext(apiRequestContext);
7443
7546
  const currentTime = (0, import_utils16.getCurrentUnixTime)();
7444
7547
  this.#createTime = currentTime;
7445
- this.#lastStatusUpdateTime = currentTime;
7446
7548
  this.#status = "free";
7549
+ this.#lastStatusUpdateTime = currentTime;
7447
7550
  this.#incognito = incognito === false ? false : true;
7448
7551
  this.#proxy = proxy?.proxyUrl ? proxy : null;
7449
7552
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -7461,7 +7564,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7461
7564
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
7462
7565
  } else {
7463
7566
  const currentTime2 = (0, import_utils16.getCurrentUnixTime)();
7464
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
7567
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
7465
7568
  const lsdPage = new CamoufoxPage(this, page, pageInfo2);
7466
7569
  this.#lsdPages.push(lsdPage);
7467
7570
  if (this.#maxViewportOfNewPage) {
@@ -7527,7 +7630,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7527
7630
  if (maxPageFreeSeconds <= 0) {
7528
7631
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
7529
7632
  }
7530
- if (maxPageFreeSeconds <= 0) {
7633
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
7531
7634
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
7532
7635
  return false;
7533
7636
  }
@@ -7537,7 +7640,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7537
7640
  }
7538
7641
  try {
7539
7642
  const maxUpdateTime = (0, import_utils16.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
7540
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
7643
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
7541
7644
  if (freePages.length === this.#lsdPages.length) {
7542
7645
  freePages = freePages.slice(1);
7543
7646
  }
@@ -7562,7 +7665,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7562
7665
  const { browserIncognitos: incognitos } = browserContextRequirements;
7563
7666
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
7564
7667
  }
7565
- async getPage(always = false) {
7668
+ async getPage(domainName = "", always = false) {
7566
7669
  if (!this.#browserContext) {
7567
7670
  throw new Error("Invalid browserContext");
7568
7671
  }
@@ -7571,7 +7674,10 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7571
7674
  return null;
7572
7675
  }
7573
7676
  try {
7574
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
7677
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
7678
+ if (!lsdPage && domainName) {
7679
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7680
+ }
7575
7681
  if (lsdPage) {
7576
7682
  lsdPage.use();
7577
7683
  this.#freeGettingLock();
@@ -7589,7 +7695,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7589
7695
  } else {
7590
7696
  pageInfo.openType = "newpage";
7591
7697
  }
7592
- lsdPage = this.#lsdPages.find((p) => p.isFree());
7698
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7593
7699
  if (lsdPage) {
7594
7700
  if (!this.#userAgent) {
7595
7701
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -7624,7 +7730,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7624
7730
  hasFreePage(pageNum = 1) {
7625
7731
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
7626
7732
  return true;
7627
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
7733
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
7628
7734
  return true;
7629
7735
  } else {
7630
7736
  return false;
@@ -7639,6 +7745,9 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7639
7745
  isIncognito() {
7640
7746
  return this.#incognito;
7641
7747
  }
7748
+ maxReservedSeconds() {
7749
+ return this.#maxReservedSeconds;
7750
+ }
7642
7751
  page(pageIdx) {
7643
7752
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
7644
7753
  return lsdPage ? lsdPage : null;
@@ -7750,7 +7859,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7750
7859
  throw new Error(`Invalid camoufox browser parameter`);
7751
7860
  }
7752
7861
  super();
7753
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7862
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7754
7863
  this.#browser = browser;
7755
7864
  this.#browserIdx = browserIdx;
7756
7865
  this.#pid = pid;
@@ -7775,7 +7884,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7775
7884
  }
7776
7885
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
7777
7886
  for (const browserContext of browserContexts) {
7778
- const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
7887
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
7779
7888
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7780
7889
  }
7781
7890
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -7836,8 +7945,8 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7836
7945
  browserContextOptions.userAgent = userAgent;
7837
7946
  }
7838
7947
  const browserContext = await this.#browser.newContext(browserContextOptions);
7839
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
7840
- const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
7948
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
7949
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
7841
7950
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7842
7951
  return lsdBrowserContext;
7843
7952
  }
@@ -8023,6 +8132,7 @@ var LsdBrowserController = class _LsdBrowserController {
8023
8132
  maxBrowserContextsPerBrowser = 10,
8024
8133
  maxPagesPerBrowserContext = 20,
8025
8134
  maxPageFreeSeconds = 900,
8135
+ maxReservedSeconds = 0,
8026
8136
  maxViewportOfNewPage = true,
8027
8137
  proxy = null,
8028
8138
  timeout = 3e4,
@@ -8039,7 +8149,7 @@ var LsdBrowserController = class _LsdBrowserController {
8039
8149
  } = options ? options : {};
8040
8150
  let browserPid = 0;
8041
8151
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
8042
- const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent, headlessUserAgent };
8152
+ const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxReservedSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent, headlessUserAgent };
8043
8153
  let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
8044
8154
  if (idx >= 0) {
8045
8155
  logwarn(`##browser controller Please use options.incognito instead when launching new browser.`);
@@ -8315,6 +8425,7 @@ var controller = new LsdBrowserController();
8315
8425
  LsdBrowserContextEvent,
8316
8426
  LsdBrowserEvent,
8317
8427
  LsdPageEvent,
8428
+ POPUP_TASK_ID,
8318
8429
  PlaywrightBrowser,
8319
8430
  PlaywrightBrowserContext,
8320
8431
  PlaywrightElement,