@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.js CHANGED
@@ -379,6 +379,7 @@ var PlaywrightPage = class extends EventEmitter {
379
379
  #lsdBrowserContext;
380
380
  #page;
381
381
  #status;
382
+ #lastStatusUpdateTime;
382
383
  #pageId;
383
384
  #closeWhenFree;
384
385
  #resquestInterceptionOptions;
@@ -643,12 +644,13 @@ var PlaywrightPage = class extends EventEmitter {
643
644
  throw new Error("Invalid paras in new LsdPage");
644
645
  }
645
646
  super();
647
+ const currentTime = getCurrentUnixTime();
646
648
  this.#lsdBrowserContext = browserContext;
647
649
  this.#page = page;
648
650
  this.#status = "free";
649
- const currentTime = getCurrentUnixTime();
650
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
651
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
651
+ this.#lastStatusUpdateTime = currentTime;
652
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
653
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
652
654
  this.#pageId = `PlaywrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
653
655
  this.#closeWhenFree = false;
654
656
  this.#resquestInterceptionOptions = [];
@@ -748,6 +750,7 @@ var PlaywrightPage = class extends EventEmitter {
748
750
  await this.#page.close();
749
751
  this.#page = null;
750
752
  this.#status = "closed";
753
+ this.#lastStatusUpdateTime = getCurrentUnixTime();
751
754
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
752
755
  return true;
753
756
  }
@@ -837,6 +840,7 @@ var PlaywrightPage = class extends EventEmitter {
837
840
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
838
841
  }
839
842
  this.#status = "free";
843
+ this.#lastStatusUpdateTime = getCurrentUnixTime();
840
844
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
841
845
  await this.clearRequestInterceptions();
842
846
  await this.clearResponseInterceptions();
@@ -872,8 +876,25 @@ var PlaywrightPage = class extends EventEmitter {
872
876
  id() {
873
877
  return this.#pageId;
874
878
  }
875
- isFree() {
876
- return this.#status === "free";
879
+ isAvailable(domainName = "") {
880
+ if (domainName) {
881
+ return this.#status === "free" && this.url().includes(domainName);
882
+ } else if (this.#status !== "free") {
883
+ return false;
884
+ } else {
885
+ const url = this.url();
886
+ if (!url || url === "about:blank") {
887
+ return true;
888
+ }
889
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
890
+ if (maxReservedSeconds <= 0) {
891
+ return true;
892
+ }
893
+ return getCurrentUnixTime() - this.#lastStatusUpdateTime >= maxReservedSeconds;
894
+ }
895
+ }
896
+ lastStatusUpdateTime() {
897
+ return this.#lastStatusUpdateTime;
877
898
  }
878
899
  async localStroage() {
879
900
  if (!this.#page) {
@@ -1068,10 +1089,7 @@ var PlaywrightPage = class extends EventEmitter {
1068
1089
  throw new Error("Invalid paras in setPageInfo");
1069
1090
  }
1070
1091
  const actPageInfo = this.#page.pageInfo;
1071
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
1072
- if (typeof lastStatusUpdateTime === "number") {
1073
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
1074
- }
1092
+ const { taskId, relatedId, misc } = pageInfo;
1075
1093
  if (typeof taskId === "number") {
1076
1094
  actPageInfo.taskId = taskId;
1077
1095
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -1302,6 +1320,7 @@ var PlaywrightPage = class extends EventEmitter {
1302
1320
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
1303
1321
  }
1304
1322
  this.#status = "busy";
1323
+ this.#lastStatusUpdateTime = getCurrentUnixTime();
1305
1324
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
1306
1325
  return true;
1307
1326
  }
@@ -1423,6 +1442,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1423
1442
  #browserContext;
1424
1443
  #browserContextCreationMethod;
1425
1444
  #userAgent;
1445
+ #maxReservedSeconds;
1426
1446
  #apiContext;
1427
1447
  #createTime;
1428
1448
  #lastStatusUpdateTime;
@@ -1441,9 +1461,8 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1441
1461
  }
1442
1462
  const pages = this.#browserContext.pages();
1443
1463
  const openType = this.#lsdBrowser.browserCreationMethod();
1444
- const lastStatusUpdateTime = getCurrentUnixTime2();
1445
1464
  for (const page of pages) {
1446
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
1465
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
1447
1466
  const lsdPage = new PlaywrightPage(this, page, pageInfo);
1448
1467
  this.#lsdPages.push(lsdPage);
1449
1468
  if (this.#maxViewportOfNewPage) {
@@ -1458,7 +1477,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1458
1477
  }
1459
1478
  }
1460
1479
  }
1461
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
1480
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
1462
1481
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
1463
1482
  throw new Error(`Invalid lsdBrowser parameter`);
1464
1483
  }
@@ -1472,6 +1491,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1472
1491
  this.#browserContext = browserContext;
1473
1492
  this.#browserContextCreationMethod = browserContextCreationMethod;
1474
1493
  this.#userAgent = userAgent;
1494
+ this.#maxReservedSeconds = maxReservedSeconds;
1475
1495
  const apiRequestContext = browserContext.request;
1476
1496
  this.#apiContext = new PlaywrightApiContext(apiRequestContext);
1477
1497
  const currentTime = getCurrentUnixTime2();
@@ -1495,7 +1515,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1495
1515
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
1496
1516
  } else {
1497
1517
  const currentTime2 = getCurrentUnixTime2();
1498
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
1518
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
1499
1519
  const lsdPage = new PlaywrightPage(this, page, pageInfo2);
1500
1520
  this.#lsdPages.push(lsdPage);
1501
1521
  if (this.#maxViewportOfNewPage) {
@@ -1561,7 +1581,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1561
1581
  if (maxPageFreeSeconds <= 0) {
1562
1582
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
1563
1583
  }
1564
- if (maxPageFreeSeconds <= 0) {
1584
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
1565
1585
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
1566
1586
  return false;
1567
1587
  }
@@ -1571,7 +1591,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1571
1591
  }
1572
1592
  try {
1573
1593
  const maxUpdateTime = getCurrentUnixTime2() - this.#maxPageFreeSeconds;
1574
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
1594
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
1575
1595
  if (freePages.length === this.#lsdPages.length) {
1576
1596
  freePages = freePages.slice(1);
1577
1597
  }
@@ -1596,7 +1616,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1596
1616
  const { browserIncognitos: incognitos } = browserContextRequirements;
1597
1617
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
1598
1618
  }
1599
- async getPage(always = false) {
1619
+ async getPage(domainName = "", always = false) {
1600
1620
  if (!this.#browserContext) {
1601
1621
  throw new Error("Invalid browserContext");
1602
1622
  }
@@ -1605,7 +1625,10 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1605
1625
  return null;
1606
1626
  }
1607
1627
  try {
1608
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
1628
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
1629
+ if (!lsdPage && domainName) {
1630
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1631
+ }
1609
1632
  if (lsdPage) {
1610
1633
  lsdPage.use();
1611
1634
  this.#freeGettingLock();
@@ -1623,7 +1646,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1623
1646
  } else {
1624
1647
  pageInfo.openType = "newpage";
1625
1648
  }
1626
- lsdPage = this.#lsdPages.find((p) => p.isFree());
1649
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
1627
1650
  if (lsdPage) {
1628
1651
  if (!this.#userAgent) {
1629
1652
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -1658,7 +1681,7 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1658
1681
  hasFreePage(pageNum = 1) {
1659
1682
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
1660
1683
  return true;
1661
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
1684
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
1662
1685
  return true;
1663
1686
  } else {
1664
1687
  return false;
@@ -1673,6 +1696,9 @@ var PlaywrightBrowserContext = class extends EventEmitter2 {
1673
1696
  isIncognito() {
1674
1697
  return this.#incognito;
1675
1698
  }
1699
+ maxReservedSeconds() {
1700
+ return this.#maxReservedSeconds;
1701
+ }
1676
1702
  page(pageIdx) {
1677
1703
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
1678
1704
  return lsdPage ? lsdPage : null;
@@ -1784,7 +1810,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends EventEmitter3 {
1784
1810
  throw new Error(`Invalid playwright browser parameter`);
1785
1811
  }
1786
1812
  super();
1787
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1813
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
1788
1814
  this.#browser = browser;
1789
1815
  this.#browserIdx = browserIdx;
1790
1816
  this.#pid = pid;
@@ -1809,7 +1835,7 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends EventEmitter3 {
1809
1835
  }
1810
1836
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
1811
1837
  for (const browserContext of browserContexts) {
1812
- const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
1838
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
1813
1839
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1814
1840
  }
1815
1841
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -1870,8 +1896,8 @@ var PlaywrightBrowser = class _PlaywrightBrowser extends EventEmitter3 {
1870
1896
  browserContextOptions.userAgent = userAgent;
1871
1897
  }
1872
1898
  const browserContext = await this.#browser.newContext(browserContextOptions);
1873
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
1874
- const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
1899
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
1900
+ const lsdBrowserContext = new PlaywrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
1875
1901
  this.#lsdBrowserContexts.push(lsdBrowserContext);
1876
1902
  return lsdBrowserContext;
1877
1903
  }
@@ -2253,6 +2279,7 @@ var PuppeteerPage = class extends EventEmitter4 {
2253
2279
  #lsdBrowserContext;
2254
2280
  #page;
2255
2281
  #status;
2282
+ #lastStatusUpdateTime;
2256
2283
  #pageId;
2257
2284
  #userAgent;
2258
2285
  #closeWhenFree;
@@ -2481,12 +2508,13 @@ var PuppeteerPage = class extends EventEmitter4 {
2481
2508
  throw new Error("Invalid paras in new LsdPage");
2482
2509
  }
2483
2510
  super();
2511
+ const currentTime = getCurrentUnixTime4();
2484
2512
  this.#lsdBrowserContext = browserContext;
2485
2513
  this.#page = page;
2486
2514
  this.#status = "free";
2487
- const currentTime = getCurrentUnixTime4();
2488
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
2489
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
2515
+ this.#lastStatusUpdateTime = currentTime;
2516
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
2517
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
2490
2518
  this.#pageId = `PuppeteerPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
2491
2519
  this.#userAgent = browserContext.userAgent();
2492
2520
  this.#closeWhenFree = false;
@@ -2583,6 +2611,7 @@ var PuppeteerPage = class extends EventEmitter4 {
2583
2611
  await this.#page.close();
2584
2612
  this.#page = null;
2585
2613
  this.#status = "closed";
2614
+ this.#lastStatusUpdateTime = getCurrentUnixTime4();
2586
2615
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
2587
2616
  return true;
2588
2617
  }
@@ -2672,6 +2701,7 @@ var PuppeteerPage = class extends EventEmitter4 {
2672
2701
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
2673
2702
  }
2674
2703
  this.#status = "free";
2704
+ this.#lastStatusUpdateTime = getCurrentUnixTime4();
2675
2705
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
2676
2706
  await this.clearRequestInterceptions();
2677
2707
  await this.clearResponseInterceptions();
@@ -2711,8 +2741,25 @@ var PuppeteerPage = class extends EventEmitter4 {
2711
2741
  id() {
2712
2742
  return this.#pageId;
2713
2743
  }
2714
- isFree() {
2715
- return this.#status === "free";
2744
+ isAvailable(domainName = "") {
2745
+ if (domainName) {
2746
+ return this.#status === "free" && this.url().includes(domainName);
2747
+ } else if (this.#status !== "free") {
2748
+ return false;
2749
+ } else {
2750
+ const url = this.url();
2751
+ if (!url || url === "about:blank") {
2752
+ return true;
2753
+ }
2754
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
2755
+ if (maxReservedSeconds <= 0) {
2756
+ return true;
2757
+ }
2758
+ return getCurrentUnixTime4() - this.#lastStatusUpdateTime >= maxReservedSeconds;
2759
+ }
2760
+ }
2761
+ lastStatusUpdateTime() {
2762
+ return this.#lastStatusUpdateTime;
2716
2763
  }
2717
2764
  async localStroage() {
2718
2765
  if (!this.#page) {
@@ -2906,10 +2953,7 @@ var PuppeteerPage = class extends EventEmitter4 {
2906
2953
  throw new Error("Invalid paras in setPageInfo");
2907
2954
  }
2908
2955
  const actPageInfo = this.#page.pageInfo;
2909
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
2910
- if (typeof lastStatusUpdateTime === "number") {
2911
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
2912
- }
2956
+ const { taskId, relatedId, misc } = pageInfo;
2913
2957
  if (typeof taskId === "number") {
2914
2958
  actPageInfo.taskId = taskId;
2915
2959
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -3127,6 +3171,7 @@ var PuppeteerPage = class extends EventEmitter4 {
3127
3171
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
3128
3172
  }
3129
3173
  this.#status = "busy";
3174
+ this.#lastStatusUpdateTime = getCurrentUnixTime4();
3130
3175
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
3131
3176
  return true;
3132
3177
  }
@@ -3220,6 +3265,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3220
3265
  */
3221
3266
  #bcUserAgent;
3222
3267
  #userAgent;
3268
+ #maxReservedSeconds;
3223
3269
  #createTime;
3224
3270
  #lastStatusUpdateTime;
3225
3271
  #status;
@@ -3237,9 +3283,8 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3237
3283
  }
3238
3284
  const pages = await this.#browserContext.pages();
3239
3285
  const openType = this.#lsdBrowser.browserCreationMethod();
3240
- const lastStatusUpdateTime = getCurrentUnixTime5();
3241
3286
  for (const page of pages) {
3242
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
3287
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
3243
3288
  const lsdPage = new PuppeteerPage(this, page, pageInfo);
3244
3289
  this.#lsdPages.push(lsdPage);
3245
3290
  if (this.#maxViewportOfNewPage) {
@@ -3257,7 +3302,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3257
3302
  }
3258
3303
  }
3259
3304
  }
3260
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
3305
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
3261
3306
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
3262
3307
  throw new Error(`Invalid lsdBrowser parameter`);
3263
3308
  }
@@ -3272,6 +3317,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3272
3317
  this.#browserContextCreationMethod = browserContextCreationMethod;
3273
3318
  this.#bcUserAgent = userAgent;
3274
3319
  this.#userAgent = userAgent;
3320
+ this.#maxReservedSeconds = maxReservedSeconds;
3275
3321
  const currentTime = getCurrentUnixTime5();
3276
3322
  this.#createTime = currentTime;
3277
3323
  this.#lastStatusUpdateTime = currentTime;
@@ -3298,7 +3344,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3298
3344
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
3299
3345
  } else {
3300
3346
  const currentTime2 = getCurrentUnixTime5();
3301
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
3347
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
3302
3348
  const lsdPage = new PuppeteerPage(this, page, pageInfo2);
3303
3349
  this.#lsdPages.push(lsdPage);
3304
3350
  if (this.#maxViewportOfNewPage) {
@@ -3371,7 +3417,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3371
3417
  if (maxPageFreeSeconds <= 0) {
3372
3418
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
3373
3419
  }
3374
- if (maxPageFreeSeconds <= 0) {
3420
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
3375
3421
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
3376
3422
  return false;
3377
3423
  }
@@ -3381,7 +3427,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3381
3427
  }
3382
3428
  try {
3383
3429
  const maxUpdateTime = getCurrentUnixTime5() - this.#maxPageFreeSeconds;
3384
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
3430
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
3385
3431
  if (freePages.length === this.#lsdPages.length) {
3386
3432
  freePages = freePages.slice(1);
3387
3433
  }
@@ -3406,7 +3452,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3406
3452
  const { browserIncognitos: incognitos } = browserContextRequirements;
3407
3453
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
3408
3454
  }
3409
- async getPage(always = false) {
3455
+ async getPage(domainName = "", always = false) {
3410
3456
  if (!this.#browserContext) {
3411
3457
  throw new Error("Invalid browserContext");
3412
3458
  }
@@ -3418,7 +3464,10 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3418
3464
  if (this.#lsdPages.length === 0) {
3419
3465
  await sleep2(1e3);
3420
3466
  }
3421
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
3467
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
3468
+ if (!lsdPage && domainName) {
3469
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3470
+ }
3422
3471
  if (lsdPage) {
3423
3472
  lsdPage.use();
3424
3473
  this.#freeGettingLock();
@@ -3438,7 +3487,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3438
3487
  } else {
3439
3488
  pageInfo.openType = "newpage";
3440
3489
  }
3441
- lsdPage = this.#lsdPages.find((p) => p.isFree());
3490
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
3442
3491
  if (lsdPage) {
3443
3492
  if (!this.#userAgent) {
3444
3493
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -3473,7 +3522,7 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3473
3522
  hasFreePage(pageNum = 1) {
3474
3523
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
3475
3524
  return true;
3476
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
3525
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
3477
3526
  return true;
3478
3527
  } else {
3479
3528
  return false;
@@ -3488,6 +3537,9 @@ var PuppeteerBrowserContext = class extends EventEmitter5 {
3488
3537
  isFree() {
3489
3538
  return this.#status === "free";
3490
3539
  }
3540
+ maxReservedSeconds() {
3541
+ return this.#maxReservedSeconds;
3542
+ }
3491
3543
  page(pageIdx) {
3492
3544
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
3493
3545
  return lsdPage ? lsdPage : null;
@@ -3602,7 +3654,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends EventEmitter6 {
3602
3654
  throw new Error(`Invalid puppeteer browser parameter`);
3603
3655
  }
3604
3656
  super();
3605
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3657
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
3606
3658
  this.#browser = browser;
3607
3659
  this.#browserIdx = browserIdx;
3608
3660
  this.#pid = pid;
@@ -3624,7 +3676,7 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends EventEmitter6 {
3624
3676
  const browserContexts = browser.browserContexts();
3625
3677
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : false;
3626
3678
  for (const browserContext of browserContexts) {
3627
- const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), this.#userAgent(), maxViewportOfNewPage);
3679
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), this.#userAgent(), maxReservedSeconds, maxViewportOfNewPage);
3628
3680
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3629
3681
  }
3630
3682
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -3678,8 +3730,8 @@ var PuppeteerBrowser = class _PuppeteerBrowser extends EventEmitter6 {
3678
3730
  userAgent = lsdLaunchOptions.headlessUserAgent;
3679
3731
  }
3680
3732
  const browserContext = await this.#browser.createBrowserContext(browserContextOptions);
3681
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
3682
- const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
3733
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
3734
+ const lsdBrowserContext = new PuppeteerBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
3683
3735
  this.#lsdBrowserContexts.push(lsdBrowserContext);
3684
3736
  return lsdBrowserContext;
3685
3737
  }
@@ -4010,7 +4062,10 @@ var CheerioPage = class extends EventEmitter7 {
4010
4062
  id() {
4011
4063
  throw new Error("Not supported in CheerioPage.");
4012
4064
  }
4013
- isFree() {
4065
+ isAvailable() {
4066
+ throw new Error("Not supported in CheerioPage.");
4067
+ }
4068
+ lastStatusUpdateTime() {
4014
4069
  throw new Error("Not supported in CheerioPage.");
4015
4070
  }
4016
4071
  load(html, isHtml = true) {
@@ -4443,6 +4498,7 @@ var PatchrightPage = class extends EventEmitter8 {
4443
4498
  #lsdBrowserContext;
4444
4499
  #page;
4445
4500
  #status;
4501
+ #lastStatusUpdateTime;
4446
4502
  #pageId;
4447
4503
  #closeWhenFree;
4448
4504
  #resquestInterceptionOptions;
@@ -4707,12 +4763,13 @@ var PatchrightPage = class extends EventEmitter8 {
4707
4763
  throw new Error("Invalid paras in new LsdPage");
4708
4764
  }
4709
4765
  super();
4766
+ const currentTime = getCurrentUnixTime7();
4710
4767
  this.#lsdBrowserContext = browserContext;
4711
4768
  this.#page = page;
4712
4769
  this.#status = "free";
4713
- const currentTime = getCurrentUnixTime7();
4714
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
4715
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
4770
+ this.#lastStatusUpdateTime = currentTime;
4771
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
4772
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
4716
4773
  this.#pageId = `PatchrightPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
4717
4774
  this.#closeWhenFree = false;
4718
4775
  this.#resquestInterceptionOptions = [];
@@ -4812,6 +4869,7 @@ var PatchrightPage = class extends EventEmitter8 {
4812
4869
  await this.#page.close();
4813
4870
  this.#page = null;
4814
4871
  this.#status = "closed";
4872
+ this.#lastStatusUpdateTime = getCurrentUnixTime7();
4815
4873
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
4816
4874
  return true;
4817
4875
  }
@@ -4900,6 +4958,7 @@ var PatchrightPage = class extends EventEmitter8 {
4900
4958
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
4901
4959
  }
4902
4960
  this.#status = "free";
4961
+ this.#lastStatusUpdateTime = getCurrentUnixTime7();
4903
4962
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
4904
4963
  await this.clearRequestInterceptions();
4905
4964
  await this.clearResponseInterceptions();
@@ -4935,8 +4994,25 @@ var PatchrightPage = class extends EventEmitter8 {
4935
4994
  id() {
4936
4995
  return this.#pageId;
4937
4996
  }
4938
- isFree() {
4939
- return this.#status === "free";
4997
+ isAvailable(domainName = "") {
4998
+ if (domainName) {
4999
+ return this.#status === "free" && this.url().includes(domainName);
5000
+ } else if (this.#status !== "free") {
5001
+ return false;
5002
+ } else {
5003
+ const url = this.url();
5004
+ if (!url || url === "about:blank") {
5005
+ return true;
5006
+ }
5007
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
5008
+ if (maxReservedSeconds <= 0) {
5009
+ return true;
5010
+ }
5011
+ return getCurrentUnixTime7() - this.#lastStatusUpdateTime >= maxReservedSeconds;
5012
+ }
5013
+ }
5014
+ lastStatusUpdateTime() {
5015
+ return this.#lastStatusUpdateTime;
4940
5016
  }
4941
5017
  async localStroage() {
4942
5018
  if (!this.#page) {
@@ -5131,10 +5207,7 @@ var PatchrightPage = class extends EventEmitter8 {
5131
5207
  throw new Error("Invalid paras in setPageInfo");
5132
5208
  }
5133
5209
  const actPageInfo = this.#page.pageInfo;
5134
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
5135
- if (typeof lastStatusUpdateTime === "number") {
5136
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
5137
- }
5210
+ const { taskId, relatedId, misc } = pageInfo;
5138
5211
  if (typeof taskId === "number") {
5139
5212
  actPageInfo.taskId = taskId;
5140
5213
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -5365,6 +5438,7 @@ var PatchrightPage = class extends EventEmitter8 {
5365
5438
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
5366
5439
  }
5367
5440
  this.#status = "busy";
5441
+ this.#lastStatusUpdateTime = getCurrentUnixTime7();
5368
5442
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
5369
5443
  return true;
5370
5444
  }
@@ -5487,10 +5561,11 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5487
5561
  #browserContext;
5488
5562
  #browserContextCreationMethod;
5489
5563
  #userAgent;
5564
+ #maxReservedSeconds;
5490
5565
  #apiContext;
5491
5566
  #createTime;
5492
- #lastStatusUpdateTime;
5493
5567
  #status;
5568
+ #lastStatusUpdateTime;
5494
5569
  #incognito;
5495
5570
  #proxy;
5496
5571
  #maxPagesPerBrowserContext;
@@ -5505,9 +5580,8 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5505
5580
  }
5506
5581
  const pages = this.#browserContext.pages();
5507
5582
  const openType = this.#lsdBrowser.browserCreationMethod();
5508
- const lastStatusUpdateTime = getCurrentUnixTime8();
5509
5583
  for (const page of pages) {
5510
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
5584
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
5511
5585
  const lsdPage = new PatchrightPage(this, page, pageInfo);
5512
5586
  this.#lsdPages.push(lsdPage);
5513
5587
  if (this.#maxViewportOfNewPage) {
@@ -5522,7 +5596,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5522
5596
  }
5523
5597
  }
5524
5598
  }
5525
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
5599
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
5526
5600
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
5527
5601
  throw new Error(`Invalid lsdBrowser parameter`);
5528
5602
  }
@@ -5536,12 +5610,13 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5536
5610
  this.#browserContext = browserContext;
5537
5611
  this.#browserContextCreationMethod = browserContextCreationMethod;
5538
5612
  this.#userAgent = userAgent;
5613
+ this.#maxReservedSeconds = maxReservedSeconds;
5539
5614
  const apiRequestContext = browserContext.request;
5540
5615
  this.#apiContext = new PatchrightApiContext(apiRequestContext);
5541
5616
  const currentTime = getCurrentUnixTime8();
5542
5617
  this.#createTime = currentTime;
5543
- this.#lastStatusUpdateTime = currentTime;
5544
5618
  this.#status = "free";
5619
+ this.#lastStatusUpdateTime = currentTime;
5545
5620
  this.#incognito = incognito === false ? false : true;
5546
5621
  this.#proxy = proxy?.proxyUrl ? proxy : null;
5547
5622
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -5559,7 +5634,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5559
5634
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
5560
5635
  } else {
5561
5636
  const currentTime2 = getCurrentUnixTime8();
5562
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
5637
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
5563
5638
  const lsdPage = new PatchrightPage(this, page, pageInfo2);
5564
5639
  this.#lsdPages.push(lsdPage);
5565
5640
  if (this.#maxViewportOfNewPage) {
@@ -5625,7 +5700,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5625
5700
  if (maxPageFreeSeconds <= 0) {
5626
5701
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
5627
5702
  }
5628
- if (maxPageFreeSeconds <= 0) {
5703
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
5629
5704
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
5630
5705
  return false;
5631
5706
  }
@@ -5635,7 +5710,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5635
5710
  }
5636
5711
  try {
5637
5712
  const maxUpdateTime = getCurrentUnixTime8() - this.#maxPageFreeSeconds;
5638
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
5713
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
5639
5714
  if (freePages.length === this.#lsdPages.length) {
5640
5715
  freePages = freePages.slice(1);
5641
5716
  }
@@ -5660,7 +5735,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5660
5735
  const { browserIncognitos: incognitos } = browserContextRequirements;
5661
5736
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
5662
5737
  }
5663
- async getPage(always = false) {
5738
+ async getPage(domainName = "", always = false) {
5664
5739
  if (!this.#browserContext) {
5665
5740
  throw new Error("Invalid browserContext");
5666
5741
  }
@@ -5669,7 +5744,10 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5669
5744
  return null;
5670
5745
  }
5671
5746
  try {
5672
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
5747
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
5748
+ if (!lsdPage && domainName) {
5749
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5750
+ }
5673
5751
  if (lsdPage) {
5674
5752
  lsdPage.use();
5675
5753
  this.#freeGettingLock();
@@ -5687,7 +5765,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5687
5765
  } else {
5688
5766
  pageInfo.openType = "newpage";
5689
5767
  }
5690
- lsdPage = this.#lsdPages.find((p) => p.isFree());
5768
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
5691
5769
  if (lsdPage) {
5692
5770
  if (!this.#userAgent) {
5693
5771
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -5722,7 +5800,7 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5722
5800
  hasFreePage(pageNum = 1) {
5723
5801
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
5724
5802
  return true;
5725
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
5803
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
5726
5804
  return true;
5727
5805
  } else {
5728
5806
  return false;
@@ -5737,6 +5815,9 @@ var PatchrightBrowserContext = class extends EventEmitter9 {
5737
5815
  isIncognito() {
5738
5816
  return this.#incognito;
5739
5817
  }
5818
+ maxReservedSeconds() {
5819
+ return this.#maxReservedSeconds;
5820
+ }
5740
5821
  page(pageIdx) {
5741
5822
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
5742
5823
  return lsdPage ? lsdPage : null;
@@ -5848,7 +5929,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends EventEmitter10 {
5848
5929
  throw new Error(`Invalid playwright browser parameter`);
5849
5930
  }
5850
5931
  super();
5851
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5932
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
5852
5933
  this.#browser = browser;
5853
5934
  this.#browserIdx = browserIdx;
5854
5935
  this.#pid = pid;
@@ -5873,7 +5954,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends EventEmitter10 {
5873
5954
  }
5874
5955
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
5875
5956
  for (const browserContext of browserContexts) {
5876
- const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
5957
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
5877
5958
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5878
5959
  }
5879
5960
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -5934,8 +6015,8 @@ var PatchrightBrowser = class _PatchrightBrowser extends EventEmitter10 {
5934
6015
  browserContextOptions.userAgent = userAgent;
5935
6016
  }
5936
6017
  const browserContext = await this.#browser.newContext(browserContextOptions);
5937
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
5938
- const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
6018
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
6019
+ const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
5939
6020
  this.#lsdBrowserContexts.push(lsdBrowserContext);
5940
6021
  return lsdBrowserContext;
5941
6022
  }
@@ -6323,6 +6404,7 @@ var CamoufoxPage = class extends EventEmitter11 {
6323
6404
  #lsdBrowserContext;
6324
6405
  #page;
6325
6406
  #status;
6407
+ #lastStatusUpdateTime;
6326
6408
  #pageId;
6327
6409
  #closeWhenFree;
6328
6410
  #resquestInterceptionOptions;
@@ -6587,12 +6669,13 @@ var CamoufoxPage = class extends EventEmitter11 {
6587
6669
  throw new Error("Invalid paras in new LsdPage");
6588
6670
  }
6589
6671
  super();
6672
+ const currentTime = getCurrentUnixTime10();
6590
6673
  this.#lsdBrowserContext = browserContext;
6591
6674
  this.#page = page;
6592
6675
  this.#status = "free";
6593
- const currentTime = getCurrentUnixTime10();
6594
- const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
6595
- this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
6676
+ this.#lastStatusUpdateTime = currentTime;
6677
+ const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
6678
+ this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, taskId, relatedId, misc };
6596
6679
  this.#pageId = `CamoufoxPage-${browserIdx}-${browserContextIdx}-${pageIdx}`;
6597
6680
  this.#closeWhenFree = false;
6598
6681
  this.#resquestInterceptionOptions = [];
@@ -6678,6 +6761,7 @@ var CamoufoxPage = class extends EventEmitter11 {
6678
6761
  await this.#page.close();
6679
6762
  this.#page = null;
6680
6763
  this.#status = "closed";
6764
+ this.#lastStatusUpdateTime = getCurrentUnixTime10();
6681
6765
  loginfo(`##browser LsdPage ${this.#pageId} is closed`);
6682
6766
  return true;
6683
6767
  }
@@ -6767,6 +6851,7 @@ var CamoufoxPage = class extends EventEmitter11 {
6767
6851
  logwarn(`##browser LsdPage ${this.#pageId} is already free.`);
6768
6852
  }
6769
6853
  this.#status = "free";
6854
+ this.#lastStatusUpdateTime = getCurrentUnixTime10();
6770
6855
  logdbg(`##browser LsdPage ${this.#pageId} is freed`);
6771
6856
  await this.clearRequestInterceptions();
6772
6857
  await this.clearResponseInterceptions();
@@ -6802,8 +6887,25 @@ var CamoufoxPage = class extends EventEmitter11 {
6802
6887
  id() {
6803
6888
  return this.#pageId;
6804
6889
  }
6805
- isFree() {
6806
- return this.#status === "free";
6890
+ isAvailable(domainName = "") {
6891
+ if (domainName) {
6892
+ return this.#status === "free" && this.url().includes(domainName);
6893
+ } else if (this.#status !== "free") {
6894
+ return false;
6895
+ } else {
6896
+ const url = this.url();
6897
+ if (!url || url === "about:blank") {
6898
+ return true;
6899
+ }
6900
+ const maxReservedSeconds = this.#lsdBrowserContext.maxReservedSeconds();
6901
+ if (maxReservedSeconds <= 0) {
6902
+ return true;
6903
+ }
6904
+ return getCurrentUnixTime10() - this.#lastStatusUpdateTime >= maxReservedSeconds;
6905
+ }
6906
+ }
6907
+ lastStatusUpdateTime() {
6908
+ return this.#lastStatusUpdateTime;
6807
6909
  }
6808
6910
  async localStroage() {
6809
6911
  if (!this.#page) {
@@ -6983,10 +7085,7 @@ var CamoufoxPage = class extends EventEmitter11 {
6983
7085
  throw new Error("Invalid paras in setPageInfo");
6984
7086
  }
6985
7087
  const actPageInfo = this.#page.pageInfo;
6986
- const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
6987
- if (typeof lastStatusUpdateTime === "number") {
6988
- actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
6989
- }
7088
+ const { taskId, relatedId, misc } = pageInfo;
6990
7089
  if (typeof taskId === "number") {
6991
7090
  actPageInfo.taskId = taskId;
6992
7091
  const debug = this.#page && this.#page.pageInfo && this.#page.pageInfo.taskId < 0;
@@ -7217,6 +7316,7 @@ var CamoufoxPage = class extends EventEmitter11 {
7217
7316
  throw new Error(`Page ${this.#pageId} is already busy!!!`);
7218
7317
  }
7219
7318
  this.#status = "busy";
7319
+ this.#lastStatusUpdateTime = getCurrentUnixTime10();
7220
7320
  logdbg(`##browser LsdPage ${this.#pageId} is allocated`);
7221
7321
  return true;
7222
7322
  }
@@ -7338,10 +7438,11 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7338
7438
  #browserContext;
7339
7439
  #browserContextCreationMethod;
7340
7440
  #userAgent;
7441
+ #maxReservedSeconds;
7341
7442
  #apiContext;
7342
7443
  #createTime;
7343
- #lastStatusUpdateTime;
7344
7444
  #status;
7445
+ #lastStatusUpdateTime;
7345
7446
  #incognito;
7346
7447
  #proxy;
7347
7448
  #maxPagesPerBrowserContext;
@@ -7356,9 +7457,8 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7356
7457
  }
7357
7458
  const pages = this.#browserContext.pages();
7358
7459
  const openType = this.#lsdBrowser.browserCreationMethod();
7359
- const lastStatusUpdateTime = getCurrentUnixTime11();
7360
7460
  for (const page of pages) {
7361
- const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
7461
+ const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, taskId: 0, relatedId: 0, misc: {} };
7362
7462
  const lsdPage = new CamoufoxPage(this, page, pageInfo);
7363
7463
  this.#lsdPages.push(lsdPage);
7364
7464
  if (this.#maxViewportOfNewPage) {
@@ -7373,7 +7473,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7373
7473
  }
7374
7474
  }
7375
7475
  }
7376
- constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxViewportOfNewPage = true) {
7476
+ constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, userAgent = "", maxReservedSeconds = 0, maxViewportOfNewPage = true) {
7377
7477
  if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
7378
7478
  throw new Error(`Invalid lsdBrowser parameter`);
7379
7479
  }
@@ -7387,12 +7487,13 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7387
7487
  this.#browserContext = browserContext;
7388
7488
  this.#browserContextCreationMethod = browserContextCreationMethod;
7389
7489
  this.#userAgent = userAgent;
7490
+ this.#maxReservedSeconds = maxReservedSeconds;
7390
7491
  const apiRequestContext = browserContext.request;
7391
7492
  this.#apiContext = new CamoufoxApiContext(apiRequestContext);
7392
7493
  const currentTime = getCurrentUnixTime11();
7393
7494
  this.#createTime = currentTime;
7394
- this.#lastStatusUpdateTime = currentTime;
7395
7495
  this.#status = "free";
7496
+ this.#lastStatusUpdateTime = currentTime;
7396
7497
  this.#incognito = incognito === false ? false : true;
7397
7498
  this.#proxy = proxy?.proxyUrl ? proxy : null;
7398
7499
  this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
@@ -7410,7 +7511,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7410
7511
  logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
7411
7512
  } else {
7412
7513
  const currentTime2 = getCurrentUnixTime11();
7413
- const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
7514
+ const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
7414
7515
  const lsdPage = new CamoufoxPage(this, page, pageInfo2);
7415
7516
  this.#lsdPages.push(lsdPage);
7416
7517
  if (this.#maxViewportOfNewPage) {
@@ -7476,7 +7577,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7476
7577
  if (maxPageFreeSeconds <= 0) {
7477
7578
  maxPageFreeSeconds = this.#maxPageFreeSeconds;
7478
7579
  }
7479
- if (maxPageFreeSeconds <= 0) {
7580
+ if (maxPageFreeSeconds <= 0 || maxPageFreeSeconds < this.#maxReservedSeconds + 60) {
7480
7581
  logwarn(`##browser LsdBrowserContext please set valid maxPageFreeSeconds to close free pages`);
7481
7582
  return false;
7482
7583
  }
@@ -7486,7 +7587,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7486
7587
  }
7487
7588
  try {
7488
7589
  const maxUpdateTime = getCurrentUnixTime11() - this.#maxPageFreeSeconds;
7489
- let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
7590
+ let freePages = this.#lsdPages.filter((p) => p.status() === "free" && p.lastStatusUpdateTime() < maxUpdateTime);
7490
7591
  if (freePages.length === this.#lsdPages.length) {
7491
7592
  freePages = freePages.slice(1);
7492
7593
  }
@@ -7511,7 +7612,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7511
7612
  const { browserIncognitos: incognitos } = browserContextRequirements;
7512
7613
  return incognitos.length === 0 || incognitos.includes(this.#incognito);
7513
7614
  }
7514
- async getPage(always = false) {
7615
+ async getPage(domainName = "", always = false) {
7515
7616
  if (!this.#browserContext) {
7516
7617
  throw new Error("Invalid browserContext");
7517
7618
  }
@@ -7520,7 +7621,10 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7520
7621
  return null;
7521
7622
  }
7522
7623
  try {
7523
- let lsdPage = this.#lsdPages.find((p) => p.isFree());
7624
+ let lsdPage = this.#lsdPages.find((p) => p.isAvailable(domainName));
7625
+ if (!lsdPage && domainName) {
7626
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7627
+ }
7524
7628
  if (lsdPage) {
7525
7629
  lsdPage.use();
7526
7630
  this.#freeGettingLock();
@@ -7538,7 +7642,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7538
7642
  } else {
7539
7643
  pageInfo.openType = "newpage";
7540
7644
  }
7541
- lsdPage = this.#lsdPages.find((p) => p.isFree());
7645
+ lsdPage = this.#lsdPages.find((p) => p.isAvailable());
7542
7646
  if (lsdPage) {
7543
7647
  if (!this.#userAgent) {
7544
7648
  const userAgent = await lsdPage.evaluate(() => navigator.userAgent);
@@ -7573,7 +7677,7 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7573
7677
  hasFreePage(pageNum = 1) {
7574
7678
  if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
7575
7679
  return true;
7576
- } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
7680
+ } else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isAvailable()).length > pageNum) {
7577
7681
  return true;
7578
7682
  } else {
7579
7683
  return false;
@@ -7588,6 +7692,9 @@ var CamoufoxBrowserContext = class extends EventEmitter12 {
7588
7692
  isIncognito() {
7589
7693
  return this.#incognito;
7590
7694
  }
7695
+ maxReservedSeconds() {
7696
+ return this.#maxReservedSeconds;
7697
+ }
7591
7698
  page(pageIdx) {
7592
7699
  const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
7593
7700
  return lsdPage ? lsdPage : null;
@@ -7699,7 +7806,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends EventEmitter13 {
7699
7806
  throw new Error(`Invalid camoufox browser parameter`);
7700
7807
  }
7701
7808
  super();
7702
- const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7809
+ const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxReservedSeconds = 0, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
7703
7810
  this.#browser = browser;
7704
7811
  this.#browserIdx = browserIdx;
7705
7812
  this.#pid = pid;
@@ -7724,7 +7831,7 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends EventEmitter13 {
7724
7831
  }
7725
7832
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
7726
7833
  for (const browserContext of browserContexts) {
7727
- const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxViewportOfNewPage);
7834
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), "", maxReservedSeconds, maxViewportOfNewPage);
7728
7835
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7729
7836
  }
7730
7837
  browser.on("disconnected" /* BROWSER_DISCONNECTED */, () => {
@@ -7785,8 +7892,8 @@ var CamoufoxBrowser = class _CamoufoxBrowser extends EventEmitter13 {
7785
7892
  browserContextOptions.userAgent = userAgent;
7786
7893
  }
7787
7894
  const browserContext = await this.#browser.newContext(browserContextOptions);
7788
- const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
7789
- const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxViewportOfNewPage);
7895
+ const { maxReservedSeconds, maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
7896
+ const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), userAgent, maxReservedSeconds, maxViewportOfNewPage);
7790
7897
  this.#lsdBrowserContexts.push(lsdBrowserContext);
7791
7898
  return lsdBrowserContext;
7792
7899
  }
@@ -7972,6 +8079,7 @@ var LsdBrowserController = class _LsdBrowserController {
7972
8079
  maxBrowserContextsPerBrowser = 10,
7973
8080
  maxPagesPerBrowserContext = 20,
7974
8081
  maxPageFreeSeconds = 900,
8082
+ maxReservedSeconds = 0,
7975
8083
  maxViewportOfNewPage = true,
7976
8084
  proxy = null,
7977
8085
  timeout = 3e4,
@@ -7988,7 +8096,7 @@ var LsdBrowserController = class _LsdBrowserController {
7988
8096
  } = options ? options : {};
7989
8097
  let browserPid = 0;
7990
8098
  const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
7991
- const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent, headlessUserAgent };
8099
+ const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxReservedSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent, headlessUserAgent };
7992
8100
  let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
7993
8101
  if (idx >= 0) {
7994
8102
  logwarn(`##browser controller Please use options.incognito instead when launching new browser.`);