@detiq/crawler 0.1.5 → 0.1.6

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/crawler.js CHANGED
@@ -1002,7 +1002,8 @@ async function crawlProject(opts, onProgress) {
1002
1002
  }
1003
1003
  let checkpointSuccessCount = 0;
1004
1004
  let maxSeenTotal = 0;
1005
- let lastEmittedPct = 20;
1005
+ let lastEmittedPct = 5;
1006
+ const crawlLoopStart = Date.now();
1006
1007
  const startUrl = page.url();
1007
1008
  const resumeUrls = opts.resumeUrls ?? [];
1008
1009
  const gqlIntrospectionPromise = (async () => {
@@ -1708,7 +1709,11 @@ async function crawlProject(opts, onProgress) {
1708
1709
  if (cachedLinks) {
1709
1710
  logger.info({ url, cachedCount: cachedLinks.length }, "[crawler] link-discovery: using cached recipe \u2014 AI will still run and merge");
1710
1711
  }
1711
- await onProgress?.(20, `Crawling ${visited.size} of ~${visited.size + queue.length} \xB7 ${(() => {
1712
+ const elapsedDiscoverySec = (Date.now() - crawlLoopStart) / 1e3;
1713
+ const discoveryPct = Math.round(5 + Math.min(15, elapsedDiscoverySec / 60 * 15));
1714
+ const preCapturePct = Math.max(lastEmittedPct, discoveryPct);
1715
+ lastEmittedPct = preCapturePct;
1716
+ await onProgress?.(preCapturePct, `Crawling ${visited.size} of ~${visited.size + queue.length} \xB7 ${(() => {
1712
1717
  try {
1713
1718
  return new URL(url).pathname || "/";
1714
1719
  } catch {
@@ -1719,6 +1724,13 @@ async function crawlProject(opts, onProgress) {
1719
1724
  () => document.querySelectorAll('button,a,input,select,textarea,[role="button"],[onclick],[aria-label]').length
1720
1725
  ).catch(() => 0);
1721
1726
  await waitForScreenshotReady(page);
1727
+ await onProgress?.(lastEmittedPct, `Capturing ${(() => {
1728
+ try {
1729
+ return new URL(url).pathname || "/";
1730
+ } catch {
1731
+ return "/";
1732
+ }
1733
+ })()}`);
1722
1734
  const [, elements, nextLinks, atElements] = await Promise.all([
1723
1735
  page.screenshot({ path: shotPath, fullPage: true }).then(() => AppBrain.saveScreenshot(opts.tenantId, opts.projectId, screen.id, shotPath, screen.version, "DESKTOP")),
1724
1736
  extractElements(stagehand, page, elementLLM ?? void 0).catch(() => []),
@@ -2158,7 +2170,8 @@ ${snippet}`,
2158
2170
  })();
2159
2171
  }
2160
2172
  discovered.push({ url, screenId: screen.id, elements: elements.length, elementFacts: elements, screenshotPath: shotPath, version: screen.version });
2161
- maxSeenTotal = Math.max(maxSeenTotal, visited.size + queue.length);
2173
+ const effectiveMax = isFinite(maxScreens) ? Math.min(visited.size + queue.length, maxScreens * 3) : visited.size + queue.length;
2174
+ maxSeenTotal = Math.max(maxSeenTotal, effectiveMax);
2162
2175
  const rawPct = 20 + Math.round(Math.min(60, visited.size / Math.max(1, maxSeenTotal) * 60));
2163
2176
  const clampedPct = Math.max(lastEmittedPct, rawPct);
2164
2177
  lastEmittedPct = clampedPct;
@@ -3399,12 +3412,14 @@ async function waitForStableDOM(page, maxWait = 8e3, stabilityMs = 400) {
3399
3412
  }
3400
3413
  }
3401
3414
  async function waitForScreenshotReady(page) {
3415
+ const hardDeadline = Date.now() + 2e4;
3416
+ const withHardCap = (p) => Promise.race([p, new Promise((resolve) => setTimeout(resolve, Math.max(0, hardDeadline - Date.now())))]);
3402
3417
  try {
3403
- await page.waitForLoadState("domcontentloaded", { timeout: 5e3 }).catch(() => {
3404
- });
3405
- await page.waitForLoadState("networkidle", { timeout: 12e3 }).catch(() => {
3406
- });
3407
- await page.evaluate(() => {
3418
+ await withHardCap(page.waitForLoadState("domcontentloaded", { timeout: 5e3 }).catch(() => {
3419
+ }));
3420
+ await withHardCap(page.waitForLoadState("networkidle", { timeout: 12e3 }).catch(() => {
3421
+ }));
3422
+ await withHardCap(page.evaluate(() => {
3408
3423
  if (document.readyState === "complete") return true;
3409
3424
  return new Promise((resolve) => {
3410
3425
  const done = () => resolve(true);
@@ -3412,15 +3427,15 @@ async function waitForScreenshotReady(page) {
3412
3427
  setTimeout(done, 4e3);
3413
3428
  });
3414
3429
  }).catch(() => {
3415
- });
3416
- await page.evaluate(async () => {
3430
+ }));
3431
+ await withHardCap(page.evaluate(async () => {
3417
3432
  const fonts = document.fonts;
3418
3433
  if (fonts?.ready) await fonts.ready;
3419
3434
  }).catch(() => {
3420
- });
3421
- await scrollToTriggerLazyLoad(page);
3422
- await waitForStableDOM(page, 1e4, 700);
3423
- await page.evaluate(async () => {
3435
+ }));
3436
+ await withHardCap(scrollToTriggerLazyLoad(page));
3437
+ await withHardCap(waitForStableDOM(page, 4e3, 700));
3438
+ await withHardCap(page.evaluate(async () => {
3424
3439
  const pending = Array.from(document.images).filter((img) => !img.complete);
3425
3440
  if (pending.length === 0) return;
3426
3441
  await Promise.race([
@@ -3431,10 +3446,10 @@ async function waitForScreenshotReady(page) {
3431
3446
  new Promise((resolve) => setTimeout(resolve, 4e3))
3432
3447
  ]);
3433
3448
  }).catch(() => {
3434
- });
3435
- await waitForStableDOM(page, 4e3, 500);
3436
- await page.waitForTimeout(250).catch(() => {
3437
- });
3449
+ }));
3450
+ await withHardCap(waitForStableDOM(page, 2e3, 500));
3451
+ await withHardCap(page.waitForTimeout(250).catch(() => {
3452
+ }));
3438
3453
  } catch {
3439
3454
  }
3440
3455
  }