@letsscrapedata/controller 0.1.0 → 0.5.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
@@ -430,6 +430,7 @@ var PlaywrightPage = class extends import_node_events.default {
430
430
  #lsdBrowserContext;
431
431
  #page;
432
432
  #status;
433
+ #lastStatusUpdateTime;
433
434
  #pageId;
434
435
  #closeWhenFree;
435
436
  #resquestInterceptionOptions;
@@ -694,12 +695,13 @@ var PlaywrightPage = class extends import_node_events.default {
694
695
  throw new Error("Invalid paras in new LsdPage");
695
696
  }
696
697
  super();
698
+ const currentTime = (0, import_utils3.getCurrentUnixTime)();
697
699
  this.#lsdBrowserContext = browserContext;
698
700
  this.#page = page;
699
701
  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 };
702
+ this.#lastStatusUpdateTime = currentTime;
703
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
704
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
703
705
  this.#pageId = `PlaywrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
704
706
  this.#closeWhenFree = false;
705
707
  this.#resquestInterceptionOptions = [];
@@ -799,6 +801,7 @@ var PlaywrightPage = class extends import_node_events.default {
799
801
  await this.#page.close();
800
802
  this.#page = null;
801
803
  this.#status = "closed";
804
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
802
805
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
803
806
  return true;
804
807
  }
@@ -888,6 +891,7 @@ var PlaywrightPage = class extends import_node_events.default {
888
891
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
889
892
  }
890
893
  this.#status = "free";
894
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
891
895
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
892
896
  await this.clearRequestInterceptions();
893
897
  await this.clearResponseInterceptions();
@@ -923,8 +927,25 @@ var PlaywrightPage = class extends import_node_events.default {
923
927
  id() {
924
928
  return this.#pageId;
925
929
  }
926
- isFree() {
927
- return this.#status === "free";
930
+ isAvailable(domainName = "") {
931
+ if (domainName) {
932
+ return this.#status === "free" && this.url().includes(domainName);
933
+ } else if (this.#status !== "free") {
934
+ return false;
935
+ } else {
936
+ const url = this.url();
937
+ if (!url || url === "about:blank") {
938
+ return true;
939
+ }
940
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
941
+ if (maxReservedSeconds <= 0) {
942
+ return true;
943
+ }
944
+ return (0, import_utils3.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
945
+ }
946
+ }
947
+ lastStatusUpdateTime() {
948
+ return this.#lastStatusUpdateTime;
928
949
  }
929
950
  async localStroage() {
930
951
  if (!this.#page) {
@@ -1119,10 +1140,7 @@ var PlaywrightPage = class extends import_node_events.default {
1119
1140
  throw new Error("Invalid paras in setPageInfo");
1120
1141
  }
1121
1142
  const actPageInfo = this.#page.pageInfo;
1122
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
1123
- if (typeof lastStatusUpdateTime === "number") {
1124
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
1125
- }
1143
+ const { taskId, relatedId, misc } = pageInfo;
1126
1144
  if (typeof taskId === "number") {
1127
1145
  actPageInfo.taskId = taskId;
1128
1146
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -1353,6 +1371,7 @@ var PlaywrightPage = class extends import_node_events.default {
1353
1371
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
1354
1372
  }
1355
1373
  this.#status = "busy";
1374
+ this.#lastStatusUpdateTime = (0, import_utils3.getCurrentUnixTime)();
1356
1375
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
1357
1376
  return true;
1358
1377
  }
@@ -1474,6 +1493,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1474
1493
  #browserContext;
1475
1494
  #browserContextCreationMethod;
1476
1495
  #userAgent;
1496
+ #maxReservedSeconds;
1477
1497
  #apiContext;
1478
1498
  #createTime;
1479
1499
  #lastStatusUpdateTime;
@@ -1492,9 +1512,8 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1492
1512
  }
1493
1513
  const pages = this.#browserContext.pages();
1494
1514
  const openType = this.#lsdBrowser.browserCreationMethod();
1495
- const lastStatusUpdateTime = (0, import_utils4.getCurrentUnixTime)();
1496
1515
  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: {} };
1516
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
1498
1517
  const lsdPage = new PlaywrightPage(this, page, pageInfo);
1499
1518
  this.#lsdPages.push(lsdPage);
1500
1519
  if (this.#maxViewportOfNewPage) {
@@ -1509,7 +1528,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1509
1528
  }
1510
1529
  }
1511
1530
  }
1512
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
1531
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
1513
1532
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
1514
1533
  throw new Error(`Invalid lsdBrowser parameter`);
1515
1534
  }
@@ -1523,6 +1542,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1523
1542
  this.#browserContext = browserContext;
1524
1543
  this.#browserContextCreationMethod = browserContextCreationMethod;
1525
1544
  this.#userAgent = userAgent;
1545
+ this.#maxReservedSeconds = maxReservedSeconds;
1526
1546
  const apiRequestContext = browserContext.request;
1527
1547
  this.#apiContext = new PlaywrightApiContext(apiRequestContext);
1528
1548
  const currentTime = (0, import_utils4.getCurrentUnixTime)();
@@ -1546,7 +1566,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1546
1566
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
1547
1567
  } else {
1548
1568
  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: {} };
1569
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
1550
1570
  const lsdPage = new PlaywrightPage(this, page, pageInfo2);
1551
1571
  this.#lsdPages.push(lsdPage);
1552
1572
  if (this.#maxViewportOfNewPage) {
@@ -1612,7 +1632,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1612
1632
  if (maxPageFreeSeconds <= 0) {
1613
1633
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
1614
1634
  }
1615
- if (maxPageFreeSeconds <= 0) {
1635
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
1616
1636
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
1617
1637
  return false;
1618
1638
  }
@@ -1622,7 +1642,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1622
1642
  }
1623
1643
  try {
1624
1644
  const maxUpdateTime = (0, import_utils4.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
1625
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
1645
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
1626
1646
  if (freePages.length === this.#lsdPages.length) {
1627
1647
  freePages = freePages.slice(1);
1628
1648
  }
@@ -1647,7 +1667,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1647
1667
  const { browserIncognitos: incognitos } = browserContextRequirements;
1648
1668
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
1649
1669
  }
1650
- async getPage(always = false) {
1670
+ async getPage(domainName = "", always = false) {
1651
1671
  if (!this.#browserContext) {
1652
1672
  throw new Error("Invalid browserContext");
1653
1673
  }
@@ -1656,7 +1676,10 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1656
1676
  return null;
1657
1677
  }
1658
1678
  try {
1659
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
1679
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
1680
+ if (!lsdPage && domainName) {
1681
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1682
+ }
1660
1683
  if (lsdPage) {
1661
1684
  lsdPage.use();
1662
1685
  this.#freeGettingLock();
@@ -1674,7 +1697,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1674
1697
  } else {
1675
1698
  pageInfo.openType = "newpage";
1676
1699
  }
1677
- lsdPage = this.#lsdPages.find((p) => p.isFree());
1700
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1678
1701
  if (lsdPage) {
1679
1702
  if (!this.#userAgent) {
1680
1703
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -1709,7 +1732,7 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1709
1732
  hasFreePage(pageNum = 1) {
1710
1733
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
1711
1734
  return true;
1712
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
1735
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
1713
1736
  return true;
1714
1737
  } else {
1715
1738
  return false;
@@ -1724,6 +1747,9 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
1724
1747
  isIncognito() {
1725
1748
  return this.#incognito;
1726
1749
  }
1750
+ maxReservedSeconds() {
1751
+ return this.#maxReservedSeconds;
1752
+ }
1727
1753
  page(pageIdx) {
1728
1754
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
1729
1755
  return lsdPage ? lsdPage : null;
@@ -1835,7 +1861,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1835
1861
  throw new Error(`Invalid playwright browser parameter`);
1836
1862
  }
1837
1863
  super();
1838
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1864
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1839
1865
  this.#browser = browser;
1840
1866
  this.#browserIdx = browserIdx;
1841
1867
  this.#pid = pid;
@@ -1860,7 +1886,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1860
1886
  }
1861
1887
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
1862
1888
  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);
1889
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
1864
1890
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1865
1891
  }
1866
1892
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -1921,8 +1947,8 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.def
1921
1947
  browserContextOptions.userAgent = userAgent;
1922
1948
  }
1923
1949
  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);
1950
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
1951
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
1926
1952
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1927
1953
  return lsdBrowserContext;
1928
1954
  }
@@ -2304,6 +2330,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2304
2330
  #lsdBrowserContext;
2305
2331
  #page;
2306
2332
  #status;
2333
+ #lastStatusUpdateTime;
2307
2334
  #pageId;
2308
2335
  #userAgent;
2309
2336
  #closeWhenFree;
@@ -2532,12 +2559,13 @@ var PuppeteerPage = class extends import_node_events4.default {
2532
2559
  throw new Error("Invalid paras in new LsdPage");
2533
2560
  }
2534
2561
  super();
2562
+ const currentTime = (0, import_utils7.getCurrentUnixTime)();
2535
2563
  this.#lsdBrowserContext = browserContext;
2536
2564
  this.#page = page;
2537
2565
  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 };
2566
+ this.#lastStatusUpdateTime = currentTime;
2567
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
2568
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
2541
2569
  this.#pageId = `PuppeteerPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
2542
2570
  this.#userAgent = browserContext.userAgent();
2543
2571
  this.#closeWhenFree = false;
@@ -2634,6 +2662,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2634
2662
  await this.#page.close();
2635
2663
  this.#page = null;
2636
2664
  this.#status = "closed";
2665
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
2637
2666
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
2638
2667
  return true;
2639
2668
  }
@@ -2723,6 +2752,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2723
2752
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
2724
2753
  }
2725
2754
  this.#status = "free";
2755
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
2726
2756
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
2727
2757
  await this.clearRequestInterceptions();
2728
2758
  await this.clearResponseInterceptions();
@@ -2762,8 +2792,25 @@ var PuppeteerPage = class extends import_node_events4.default {
2762
2792
  id() {
2763
2793
  return this.#pageId;
2764
2794
  }
2765
- isFree() {
2766
- return this.#status === "free";
2795
+ isAvailable(domainName = "") {
2796
+ if (domainName) {
2797
+ return this.#status === "free" && this.url().includes(domainName);
2798
+ } else if (this.#status !== "free") {
2799
+ return false;
2800
+ } else {
2801
+ const url = this.url();
2802
+ if (!url || url === "about:blank") {
2803
+ return true;
2804
+ }
2805
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
2806
+ if (maxReservedSeconds <= 0) {
2807
+ return true;
2808
+ }
2809
+ return (0, import_utils7.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
2810
+ }
2811
+ }
2812
+ lastStatusUpdateTime() {
2813
+ return this.#lastStatusUpdateTime;
2767
2814
  }
2768
2815
  async localStroage() {
2769
2816
  if (!this.#page) {
@@ -2957,10 +3004,7 @@ var PuppeteerPage = class extends import_node_events4.default {
2957
3004
  throw new Error("Invalid paras in setPageInfo");
2958
3005
  }
2959
3006
  const actPageInfo = this.#page.pageInfo;
2960
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
2961
- if (typeof lastStatusUpdateTime === "number") {
2962
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
2963
- }
3007
+ const { taskId, relatedId, misc } = pageInfo;
2964
3008
  if (typeof taskId === "number") {
2965
3009
  actPageInfo.taskId = taskId;
2966
3010
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -3178,6 +3222,7 @@ var PuppeteerPage = class extends import_node_events4.default {
3178
3222
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
3179
3223
  }
3180
3224
  this.#status = "busy";
3225
+ this.#lastStatusUpdateTime = (0, import_utils7.getCurrentUnixTime)();
3181
3226
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
3182
3227
  return true;
3183
3228
  }
@@ -3271,6 +3316,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3271
3316
  */
3272
3317
  #bcUserAgent;
3273
3318
  #userAgent;
3319
+ #maxReservedSeconds;
3274
3320
  #createTime;
3275
3321
  #lastStatusUpdateTime;
3276
3322
  #status;
@@ -3288,9 +3334,8 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3288
3334
  }
3289
3335
  const pages = await this.#browserContext.pages();
3290
3336
  const openType = this.#lsdBrowser.browserCreationMethod();
3291
- const lastStatusUpdateTime = (0, import_utils8.getCurrentUnixTime)();
3292
3337
  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: {} };
3338
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
3294
3339
  const lsdPage = new PuppeteerPage(this, page, pageInfo);
3295
3340
  this.#lsdPages.push(lsdPage);
3296
3341
  if (this.#maxViewportOfNewPage) {
@@ -3308,7 +3353,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3308
3353
  }
3309
3354
  }
3310
3355
  }
3311
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
3356
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
3312
3357
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
3313
3358
  throw new Error(`Invalid lsdBrowser parameter`);
3314
3359
  }
@@ -3323,6 +3368,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3323
3368
  this.#browserContextCreationMethod = browserContextCreationMethod;
3324
3369
  this.#bcUserAgent = userAgent;
3325
3370
  this.#userAgent = userAgent;
3371
+ this.#maxReservedSeconds = maxReservedSeconds;
3326
3372
  const currentTime = (0, import_utils8.getCurrentUnixTime)();
3327
3373
  this.#createTime = currentTime;
3328
3374
  this.#lastStatusUpdateTime = currentTime;
@@ -3349,7 +3395,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3349
3395
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
3350
3396
  } else {
3351
3397
  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: {} };
3398
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
3353
3399
  const lsdPage = new PuppeteerPage(this, page, pageInfo2);
3354
3400
  this.#lsdPages.push(lsdPage);
3355
3401
  if (this.#maxViewportOfNewPage) {
@@ -3422,7 +3468,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3422
3468
  if (maxPageFreeSeconds <= 0) {
3423
3469
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
3424
3470
  }
3425
- if (maxPageFreeSeconds <= 0) {
3471
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
3426
3472
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
3427
3473
  return false;
3428
3474
  }
@@ -3432,7 +3478,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3432
3478
  }
3433
3479
  try {
3434
3480
  const maxUpdateTime = (0, import_utils8.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
3435
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
3481
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
3436
3482
  if (freePages.length === this.#lsdPages.length) {
3437
3483
  freePages = freePages.slice(1);
3438
3484
  }
@@ -3457,7 +3503,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3457
3503
  const { browserIncognitos: incognitos } = browserContextRequirements;
3458
3504
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
3459
3505
  }
3460
- async getPage(always = false) {
3506
+ async getPage(domainName = "", always = false) {
3461
3507
  if (!this.#browserContext) {
3462
3508
  throw new Error("Invalid browserContext");
3463
3509
  }
@@ -3469,7 +3515,10 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3469
3515
  if (this.#lsdPages.length === 0) {
3470
3516
  await (0, import_utils8.sleep)(1e3);
3471
3517
  }
3472
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
3518
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
3519
+ if (!lsdPage && domainName) {
3520
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3521
+ }
3473
3522
  if (lsdPage) {
3474
3523
  lsdPage.use();
3475
3524
  this.#freeGettingLock();
@@ -3489,7 +3538,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3489
3538
  } else {
3490
3539
  pageInfo.openType = "newpage";
3491
3540
  }
3492
- lsdPage = this.#lsdPages.find((p) => p.isFree());
3541
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3493
3542
  if (lsdPage) {
3494
3543
  if (!this.#userAgent) {
3495
3544
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -3524,7 +3573,7 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3524
3573
  hasFreePage(pageNum = 1) {
3525
3574
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
3526
3575
  return true;
3527
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
3576
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
3528
3577
  return true;
3529
3578
  } else {
3530
3579
  return false;
@@ -3539,6 +3588,9 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
3539
3588
  isFree() {
3540
3589
  return this.#status === "free";
3541
3590
  }
3591
+ maxReservedSeconds() {
3592
+ return this.#maxReservedSeconds;
3593
+ }
3542
3594
  page(pageIdx) {
3543
3595
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
3544
3596
  return lsdPage ? lsdPage : null;
@@ -3653,7 +3705,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3653
3705
  throw new Error(`Invalid puppeteer browser parameter`);
3654
3706
  }
3655
3707
  super();
3656
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3708
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3657
3709
  this.#browser = browser;
3658
3710
  this.#browserIdx = browserIdx;
3659
3711
  this.#pid = pid;
@@ -3675,7 +3727,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3675
3727
  const browserContexts = browser.browserContexts();
3676
3728
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : false;
3677
3729
  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);
3730
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), this.#userAgent(), maxReservedSeconds, maxViewportOfNewPage);
3679
3731
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3680
3732
  }
3681
3733
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -3729,8 +3781,8 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.defau
3729
3781
  userAgent = lsdLaunchOptions.headlessUserAgent;
3730
3782
  }
3731
3783
  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);
3784
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
3785
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
3734
3786
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3735
3787
  return lsdBrowserContext;
3736
3788
  }
@@ -4061,7 +4113,10 @@ var CheerioPage = class extends import_node_events7.default {
4061
4113
  id() {
4062
4114
  throw new Error("Not supported in CheerioPage.");
4063
4115
  }
4064
- isFree() {
4116
+ isAvailable() {
4117
+ throw new Error("Not supported in CheerioPage.");
4118
+ }
4119
+ lastStatusUpdateTime() {
4065
4120
  throw new Error("Not supported in CheerioPage.");
4066
4121
  }
4067
4122
  load(html, isHtml = true) {
@@ -4494,6 +4549,7 @@ var PatchrightPage = class extends import_node_events8.default {
4494
4549
  #lsdBrowserContext;
4495
4550
  #page;
4496
4551
  #status;
4552
+ #lastStatusUpdateTime;
4497
4553
  #pageId;
4498
4554
  #closeWhenFree;
4499
4555
  #resquestInterceptionOptions;
@@ -4758,12 +4814,13 @@ var PatchrightPage = class extends import_node_events8.default {
4758
4814
  throw new Error("Invalid paras in new LsdPage");
4759
4815
  }
4760
4816
  super();
4817
+ const currentTime = (0, import_utils11.getCurrentUnixTime)();
4761
4818
  this.#lsdBrowserContext = browserContext;
4762
4819
  this.#page = page;
4763
4820
  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 };
4821
+ this.#lastStatusUpdateTime = currentTime;
4822
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
4823
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
4767
4824
  this.#pageId = `PatchrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
4768
4825
  this.#closeWhenFree = false;
4769
4826
  this.#resquestInterceptionOptions = [];
@@ -4863,6 +4920,7 @@ var PatchrightPage = class extends import_node_events8.default {
4863
4920
  await this.#page.close();
4864
4921
  this.#page = null;
4865
4922
  this.#status = "closed";
4923
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
4866
4924
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
4867
4925
  return true;
4868
4926
  }
@@ -4951,6 +5009,7 @@ var PatchrightPage = class extends import_node_events8.default {
4951
5009
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
4952
5010
  }
4953
5011
  this.#status = "free";
5012
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
4954
5013
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
4955
5014
  await this.clearRequestInterceptions();
4956
5015
  await this.clearResponseInterceptions();
@@ -4986,8 +5045,25 @@ var PatchrightPage = class extends import_node_events8.default {
4986
5045
  id() {
4987
5046
  return this.#pageId;
4988
5047
  }
4989
- isFree() {
4990
- return this.#status === "free";
5048
+ isAvailable(domainName = "") {
5049
+ if (domainName) {
5050
+ return this.#status === "free" && this.url().includes(domainName);
5051
+ } else if (this.#status !== "free") {
5052
+ return false;
5053
+ } else {
5054
+ const url = this.url();
5055
+ if (!url || url === "about:blank") {
5056
+ return true;
5057
+ }
5058
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
5059
+ if (maxReservedSeconds <= 0) {
5060
+ return true;
5061
+ }
5062
+ return (0, import_utils11.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
5063
+ }
5064
+ }
5065
+ lastStatusUpdateTime() {
5066
+ return this.#lastStatusUpdateTime;
4991
5067
  }
4992
5068
  async localStroage() {
4993
5069
  if (!this.#page) {
@@ -5182,10 +5258,7 @@ var PatchrightPage = class extends import_node_events8.default {
5182
5258
  throw new Error("Invalid paras in setPageInfo");
5183
5259
  }
5184
5260
  const actPageInfo = this.#page.pageInfo;
5185
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
5186
- if (typeof lastStatusUpdateTime === "number") {
5187
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
5188
- }
5261
+ const { taskId, relatedId, misc } = pageInfo;
5189
5262
  if (typeof taskId === "number") {
5190
5263
  actPageInfo.taskId = taskId;
5191
5264
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -5416,6 +5489,7 @@ var PatchrightPage = class extends import_node_events8.default {
5416
5489
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
5417
5490
  }
5418
5491
  this.#status = "busy";
5492
+ this.#lastStatusUpdateTime = (0, import_utils11.getCurrentUnixTime)();
5419
5493
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
5420
5494
  return true;
5421
5495
  }
@@ -5538,10 +5612,11 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5538
5612
  #browserContext;
5539
5613
  #browserContextCreationMethod;
5540
5614
  #userAgent;
5615
+ #maxReservedSeconds;
5541
5616
  #apiContext;
5542
5617
  #createTime;
5543
- #lastStatusUpdateTime;
5544
5618
  #status;
5619
+ #lastStatusUpdateTime;
5545
5620
  #incognito;
5546
5621
  #proxy;
5547
5622
  #maxPagesPerBrowserContext;
@@ -5556,9 +5631,8 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5556
5631
  }
5557
5632
  const pages = this.#browserContext.pages();
5558
5633
  const openType = this.#lsdBrowser.browserCreationMethod();
5559
- const lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
5560
5634
  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: {} };
5635
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
5562
5636
  const lsdPage = new PatchrightPage(this, page, pageInfo);
5563
5637
  this.#lsdPages.push(lsdPage);
5564
5638
  if (this.#maxViewportOfNewPage) {
@@ -5573,7 +5647,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5573
5647
  }
5574
5648
  }
5575
5649
  }
5576
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
5650
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
5577
5651
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
5578
5652
  throw new Error(`Invalid lsdBrowser parameter`);
5579
5653
  }
@@ -5587,12 +5661,13 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5587
5661
  this.#browserContext = browserContext;
5588
5662
  this.#browserContextCreationMethod = browserContextCreationMethod;
5589
5663
  this.#userAgent = userAgent;
5664
+ this.#maxReservedSeconds = maxReservedSeconds;
5590
5665
  const apiRequestContext = browserContext.request;
5591
5666
  this.#apiContext = new PatchrightApiContext(apiRequestContext);
5592
5667
  const currentTime = (0, import_utils12.getCurrentUnixTime)();
5593
5668
  this.#createTime = currentTime;
5594
- this.#lastStatusUpdateTime = currentTime;
5595
5669
  this.#status = "free";
5670
+ this.#lastStatusUpdateTime = currentTime;
5596
5671
  this.#incognito = incognito === false ? false : true;
5597
5672
  this.#proxy = proxy?.proxyUrl ? proxy : null;
5598
5673
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -5610,7 +5685,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5610
5685
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
5611
5686
  } else {
5612
5687
  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: {} };
5688
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
5614
5689
  const lsdPage = new PatchrightPage(this, page, pageInfo2);
5615
5690
  this.#lsdPages.push(lsdPage);
5616
5691
  if (this.#maxViewportOfNewPage) {
@@ -5676,7 +5751,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5676
5751
  if (maxPageFreeSeconds <= 0) {
5677
5752
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
5678
5753
  }
5679
- if (maxPageFreeSeconds <= 0) {
5754
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
5680
5755
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
5681
5756
  return false;
5682
5757
  }
@@ -5686,7 +5761,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5686
5761
  }
5687
5762
  try {
5688
5763
  const maxUpdateTime = (0, import_utils12.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
5689
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
5764
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
5690
5765
  if (freePages.length === this.#lsdPages.length) {
5691
5766
  freePages = freePages.slice(1);
5692
5767
  }
@@ -5711,7 +5786,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5711
5786
  const { browserIncognitos: incognitos } = browserContextRequirements;
5712
5787
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
5713
5788
  }
5714
- async getPage(always = false) {
5789
+ async getPage(domainName = "", always = false) {
5715
5790
  if (!this.#browserContext) {
5716
5791
  throw new Error("Invalid browserContext");
5717
5792
  }
@@ -5720,7 +5795,10 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5720
5795
  return null;
5721
5796
  }
5722
5797
  try {
5723
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
5798
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
5799
+ if (!lsdPage && domainName) {
5800
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5801
+ }
5724
5802
  if (lsdPage) {
5725
5803
  lsdPage.use();
5726
5804
  this.#freeGettingLock();
@@ -5738,7 +5816,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5738
5816
  } else {
5739
5817
  pageInfo.openType = "newpage";
5740
5818
  }
5741
- lsdPage = this.#lsdPages.find((p) => p.isFree());
5819
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5742
5820
  if (lsdPage) {
5743
5821
  if (!this.#userAgent) {
5744
5822
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -5773,7 +5851,7 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5773
5851
  hasFreePage(pageNum = 1) {
5774
5852
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
5775
5853
  return true;
5776
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
5854
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
5777
5855
  return true;
5778
5856
  } else {
5779
5857
  return false;
@@ -5788,6 +5866,9 @@ var PatchrightBrowserContext = class extends import_node_events9.default {
5788
5866
  isIncognito() {
5789
5867
  return this.#incognito;
5790
5868
  }
5869
+ maxReservedSeconds() {
5870
+ return this.#maxReservedSeconds;
5871
+ }
5791
5872
  page(pageIdx) {
5792
5873
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
5793
5874
  return lsdPage ? lsdPage : null;
@@ -5899,7 +5980,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5899
5980
  throw new Error(`Invalid playwright browser parameter`);
5900
5981
  }
5901
5982
  super();
5902
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5983
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5903
5984
  this.#browser = browser;
5904
5985
  this.#browserIdx = browserIdx;
5905
5986
  this.#pid = pid;
@@ -5924,7 +6005,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5924
6005
  }
5925
6006
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
5926
6007
  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);
6008
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
5928
6009
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5929
6010
  }
5930
6011
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -5985,8 +6066,8 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
5985
6066
  browserContextOptions.userAgent = userAgent;
5986
6067
  }
5987
6068
  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);
6069
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
6070
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
5990
6071
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5991
6072
  return lsdBrowserContext;
5992
6073
  }
@@ -6374,6 +6455,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6374
6455
  #lsdBrowserContext;
6375
6456
  #page;
6376
6457
  #status;
6458
+ #lastStatusUpdateTime;
6377
6459
  #pageId;
6378
6460
  #closeWhenFree;
6379
6461
  #resquestInterceptionOptions;
@@ -6638,12 +6720,13 @@ var CamoufoxPage = class extends import_node_events11.default {
6638
6720
  throw new Error("Invalid paras in new LsdPage");
6639
6721
  }
6640
6722
  super();
6723
+ const currentTime = (0, import_utils15.getCurrentUnixTime)();
6641
6724
  this.#lsdBrowserContext = browserContext;
6642
6725
  this.#page = page;
6643
6726
  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 };
6727
+ this.#lastStatusUpdateTime = currentTime;
6728
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
6729
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
6647
6730
  this.#pageId = `CamoufoxPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
6648
6731
  this.#closeWhenFree = false;
6649
6732
  this.#resquestInterceptionOptions = [];
@@ -6729,6 +6812,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6729
6812
  await this.#page.close();
6730
6813
  this.#page = null;
6731
6814
  this.#status = "closed";
6815
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
6732
6816
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
6733
6817
  return true;
6734
6818
  }
@@ -6818,6 +6902,7 @@ var CamoufoxPage = class extends import_node_events11.default {
6818
6902
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
6819
6903
  }
6820
6904
  this.#status = "free";
6905
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
6821
6906
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
6822
6907
  await this.clearRequestInterceptions();
6823
6908
  await this.clearResponseInterceptions();
@@ -6853,8 +6938,25 @@ var CamoufoxPage = class extends import_node_events11.default {
6853
6938
  id() {
6854
6939
  return this.#pageId;
6855
6940
  }
6856
- isFree() {
6857
- return this.#status === "free";
6941
+ isAvailable(domainName = "") {
6942
+ if (domainName) {
6943
+ return this.#status === "free" && this.url().includes(domainName);
6944
+ } else if (this.#status !== "free") {
6945
+ return false;
6946
+ } else {
6947
+ const url = this.url();
6948
+ if (!url || url === "about:blank") {
6949
+ return true;
6950
+ }
6951
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
6952
+ if (maxReservedSeconds <= 0) {
6953
+ return true;
6954
+ }
6955
+ return (0, import_utils15.getCurrentUnixTime)() - this.#lastStatusUpdateTime >= maxReservedSeconds;
6956
+ }
6957
+ }
6958
+ lastStatusUpdateTime() {
6959
+ return this.#lastStatusUpdateTime;
6858
6960
  }
6859
6961
  async localStroage() {
6860
6962
  if (!this.#page) {
@@ -7034,10 +7136,7 @@ var CamoufoxPage = class extends import_node_events11.default {
7034
7136
  throw new Error("Invalid paras in setPageInfo");
7035
7137
  }
7036
7138
  const actPageInfo = this.#page.pageInfo;
7037
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
7038
- if (typeof lastStatusUpdateTime === "number") {
7039
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
7040
- }
7139
+ const { taskId, relatedId, misc } = pageInfo;
7041
7140
  if (typeof taskId === "number") {
7042
7141
  actPageInfo.taskId = taskId;
7043
7142
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -7268,6 +7367,7 @@ var CamoufoxPage = class extends import_node_events11.default {
7268
7367
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
7269
7368
  }
7270
7369
  this.#status = "busy";
7370
+ this.#lastStatusUpdateTime = (0, import_utils15.getCurrentUnixTime)();
7271
7371
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
7272
7372
  return true;
7273
7373
  }
@@ -7389,10 +7489,11 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7389
7489
  #browserContext;
7390
7490
  #browserContextCreationMethod;
7391
7491
  #userAgent;
7492
+ #maxReservedSeconds;
7392
7493
  #apiContext;
7393
7494
  #createTime;
7394
- #lastStatusUpdateTime;
7395
7495
  #status;
7496
+ #lastStatusUpdateTime;
7396
7497
  #incognito;
7397
7498
  #proxy;
7398
7499
  #maxPagesPerBrowserContext;
@@ -7407,9 +7508,8 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7407
7508
  }
7408
7509
  const pages = this.#browserContext.pages();
7409
7510
  const openType = this.#lsdBrowser.browserCreationMethod();
7410
- const lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
7411
7511
  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: {} };
7512
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
7413
7513
  const lsdPage = new CamoufoxPage(this, page, pageInfo);
7414
7514
  this.#lsdPages.push(lsdPage);
7415
7515
  if (this.#maxViewportOfNewPage) {
@@ -7424,7 +7524,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7424
7524
  }
7425
7525
  }
7426
7526
  }
7427
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
7527
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
7428
7528
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
7429
7529
  throw new Error(`Invalid lsdBrowser parameter`);
7430
7530
  }
@@ -7438,12 +7538,13 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7438
7538
  this.#browserContext = browserContext;
7439
7539
  this.#browserContextCreationMethod = browserContextCreationMethod;
7440
7540
  this.#userAgent = userAgent;
7541
+ this.#maxReservedSeconds = maxReservedSeconds;
7441
7542
  const apiRequestContext = browserContext.request;
7442
7543
  this.#apiContext = new CamoufoxApiContext(apiRequestContext);
7443
7544
  const currentTime = (0, import_utils16.getCurrentUnixTime)();
7444
7545
  this.#createTime = currentTime;
7445
- this.#lastStatusUpdateTime = currentTime;
7446
7546
  this.#status = "free";
7547
+ this.#lastStatusUpdateTime = currentTime;
7447
7548
  this.#incognito = incognito === false ? false : true;
7448
7549
  this.#proxy = proxy?.proxyUrl ? proxy : null;
7449
7550
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -7461,7 +7562,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7461
7562
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
7462
7563
  } else {
7463
7564
  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: {} };
7565
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
7465
7566
  const lsdPage = new CamoufoxPage(this, page, pageInfo2);
7466
7567
  this.#lsdPages.push(lsdPage);
7467
7568
  if (this.#maxViewportOfNewPage) {
@@ -7527,7 +7628,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7527
7628
  if (maxPageFreeSeconds <= 0) {
7528
7629
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
7529
7630
  }
7530
- if (maxPageFreeSeconds <= 0) {
7631
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
7531
7632
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
7532
7633
  return false;
7533
7634
  }
@@ -7537,7 +7638,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7537
7638
  }
7538
7639
  try {
7539
7640
  const maxUpdateTime = (0, import_utils16.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
7540
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
7641
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
7541
7642
  if (freePages.length === this.#lsdPages.length) {
7542
7643
  freePages = freePages.slice(1);
7543
7644
  }
@@ -7562,7 +7663,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7562
7663
  const { browserIncognitos: incognitos } = browserContextRequirements;
7563
7664
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
7564
7665
  }
7565
- async getPage(always = false) {
7666
+ async getPage(domainName = "", always = false) {
7566
7667
  if (!this.#browserContext) {
7567
7668
  throw new Error("Invalid browserContext");
7568
7669
  }
@@ -7571,7 +7672,10 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7571
7672
  return null;
7572
7673
  }
7573
7674
  try {
7574
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
7675
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
7676
+ if (!lsdPage && domainName) {
7677
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7678
+ }
7575
7679
  if (lsdPage) {
7576
7680
  lsdPage.use();
7577
7681
  this.#freeGettingLock();
@@ -7589,7 +7693,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7589
7693
  } else {
7590
7694
  pageInfo.openType = "newpage";
7591
7695
  }
7592
- lsdPage = this.#lsdPages.find((p) => p.isFree());
7696
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7593
7697
  if (lsdPage) {
7594
7698
  if (!this.#userAgent) {
7595
7699
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -7624,7 +7728,7 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7624
7728
  hasFreePage(pageNum = 1) {
7625
7729
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
7626
7730
  return true;
7627
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
7731
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
7628
7732
  return true;
7629
7733
  } else {
7630
7734
  return false;
@@ -7639,6 +7743,9 @@ var CamoufoxBrowserContext = class extends import_node_events12.default {
7639
7743
  isIncognito() {
7640
7744
  return this.#incognito;
7641
7745
  }
7746
+ maxReservedSeconds() {
7747
+ return this.#maxReservedSeconds;
7748
+ }
7642
7749
  page(pageIdx) {
7643
7750
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
7644
7751
  return lsdPage ? lsdPage : null;
@@ -7750,7 +7857,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7750
7857
  throw new Error(`Invalid camoufox browser parameter`);
7751
7858
  }
7752
7859
  super();
7753
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7860
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7754
7861
  this.#browser = browser;
7755
7862
  this.#browserIdx = browserIdx;
7756
7863
  this.#pid = pid;
@@ -7775,7 +7882,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7775
7882
  }
7776
7883
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
7777
7884
  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);
7885
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
7779
7886
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7780
7887
  }
7781
7888
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -7836,8 +7943,8 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.defaul
7836
7943
  browserContextOptions.userAgent = userAgent;
7837
7944
  }
7838
7945
  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);
7946
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
7947
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
7841
7948
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7842
7949
  return lsdBrowserContext;
7843
7950
  }
@@ -8023,6 +8130,7 @@ var LsdBrowserController = class _LsdBrowserController {
8023
8130
  maxBrowserContextsPerBrowser = 10,
8024
8131
  maxPagesPerBrowserContext = 20,
8025
8132
  maxPageFreeSeconds = 900,
8133
+ maxReservedSeconds = 0,
8026
8134
  maxViewportOfNewPage = true,
8027
8135
  proxy = null,
8028
8136
  timeout = 3e4,
@@ -8039,7 +8147,7 @@ var LsdBrowserController = class _LsdBrowserController {
8039
8147
  } = options ? options : {};
8040
8148
  let browserPid = 0;
8041
8149
  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 };
8150
+ const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxReservedSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent, headlessUserAgent };
8043
8151
  let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
8044
8152
  if (idx >= 0) {
8045
8153
  logwarn(`##browser controller Please use options.incognito instead when launching new browser.`);