@qulib/core 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -8,6 +8,16 @@
8
8
  npm install @qulib/core
9
9
  ```
10
10
 
11
+ ## One-time browser setup
12
+
13
+ Qulib uses Playwright. Install Chromium once on the machine that runs scans:
14
+
15
+ ```bash
16
+ npx playwright install chromium
17
+ ```
18
+
19
+ If browsers are missing, commands fail with a short message pointing you here.
20
+
11
21
  ## Scanning authenticated apps
12
22
 
13
23
  Qulib supports three auth modes: anonymous (default), form-login, and storage-state.
@@ -1 +1 @@
1
- {"version":3,"file":"auth-detector.d.ts","sourceRoot":"","sources":["../../src/tools/auth-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAmDhE,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAgGtF"}
1
+ {"version":3,"file":"auth-detector.d.ts","sourceRoot":"","sources":["../../src/tools/auth-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AA4DhE,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAkGtF"}
@@ -1,4 +1,12 @@
1
- import { chromium } from '@playwright/test';
1
+ import { launchBrowser } from './browser.js';
2
+ async function waitNetworkIdleBestEffort(page) {
3
+ try {
4
+ await page.waitForLoadState('networkidle', { timeout: 5000 });
5
+ }
6
+ catch {
7
+ // best-effort — analytics or polling can prevent networkidle
8
+ }
9
+ }
2
10
  const OAUTH_PROVIDERS = [
3
11
  { provider: 'github', patterns: [/github/i, /sign in with github/i] },
4
12
  {
@@ -43,11 +51,12 @@ async function firstTextInputNameForLogin(page) {
43
51
  return null;
44
52
  }
45
53
  export async function detectAuth(url, timeoutMs = 15000) {
46
- const browser = await chromium.launch({ headless: true });
54
+ const browser = await launchBrowser();
47
55
  try {
48
56
  const context = await browser.newContext();
49
57
  const page = await context.newPage();
50
58
  await page.goto(url, { timeout: timeoutMs, waitUntil: 'domcontentloaded' });
59
+ await waitNetworkIdleBestEffort(page);
51
60
  let loginUrl = url;
52
61
  const looksLikeLoginPage = /login|sign[- ]?in|auth/i.test(page.url()) ||
53
62
  (await page.locator('input[type="password"]').count()) > 0;
@@ -58,6 +67,7 @@ export async function detectAuth(url, timeoutMs = 15000) {
58
67
  if (href) {
59
68
  loginUrl = new URL(href, url).toString();
60
69
  await page.goto(loginUrl, { timeout: timeoutMs, waitUntil: 'domcontentloaded' });
70
+ await waitNetworkIdleBestEffort(page);
61
71
  }
62
72
  }
63
73
  }
@@ -0,0 +1,3 @@
1
+ import { type Browser } from '@playwright/test';
2
+ export declare function launchBrowser(): Promise<Browser>;
3
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/tools/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE1D,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAYtD"}
@@ -0,0 +1,13 @@
1
+ import { chromium } from '@playwright/test';
2
+ export async function launchBrowser() {
3
+ try {
4
+ return await chromium.launch({ headless: true });
5
+ }
6
+ catch (err) {
7
+ const message = err instanceof Error ? err.message : String(err);
8
+ if (message.includes("Executable doesn't exist") || message.includes('chromium')) {
9
+ throw new Error(`Playwright Chromium browser is not installed. Run:\n\n npx playwright install chromium\n\nThen retry your qulib command. This is a one-time setup step.`);
10
+ }
11
+ throw err;
12
+ }
13
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"playwright-explorer.d.ts","sourceRoot":"","sources":["../../src/tools/playwright-explorer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAwB,KAAK,cAAc,EAAc,MAAM,sCAAsC,CAAC;AAC7G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAgBjE,qBAAa,kBAAmB,YAAW,WAAW;IAC9C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;CAqJ/E"}
1
+ {"version":3,"file":"playwright-explorer.d.ts","sourceRoot":"","sources":["../../src/tools/playwright-explorer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAwB,KAAK,cAAc,EAAc,MAAM,sCAAsC,CAAC;AAC7G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAgBjE,qBAAa,kBAAmB,YAAW,WAAW;IAC9C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;CAqJ/E"}
@@ -1,4 +1,4 @@
1
- import { chromium } from '@playwright/test';
1
+ import { launchBrowser } from './browser.js';
2
2
  import { AxeBuilder } from '@axe-core/playwright';
3
3
  import { createAuthenticatedContext } from './auth.js';
4
4
  import { RouteInventorySchema } from '../schemas/route-inventory.schema.js';
@@ -17,7 +17,7 @@ function isInternalHref(href, baseUrlStr) {
17
17
  }
18
18
  export class PlaywrightExplorer {
19
19
  async explore(baseUrl, config) {
20
- const browser = await chromium.launch({ headless: true });
20
+ const browser = await launchBrowser();
21
21
  let context;
22
22
  try {
23
23
  context = await createAuthenticatedContext(browser, config.auth, config.timeoutMs);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qulib/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Qulib — analyze deployed web apps for honest quality gaps (CLI + programmatic API)",
5
5
  "license": "MIT",
6
6
  "author": "Tapesh Nagarwal",