@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 +10 -0
- package/dist/tools/auth-detector.d.ts.map +1 -1
- package/dist/tools/auth-detector.js +12 -2
- package/dist/tools/browser.d.ts +3 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +13 -0
- package/dist/tools/playwright-explorer.d.ts.map +1 -1
- package/dist/tools/playwright-explorer.js +2 -2
- package/package.json +1 -1
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;
|
|
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 {
|
|
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
|
|
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 @@
|
|
|
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":"
|
|
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 {
|
|
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
|
|
20
|
+
const browser = await launchBrowser();
|
|
21
21
|
let context;
|
|
22
22
|
try {
|
|
23
23
|
context = await createAuthenticatedContext(browser, config.auth, config.timeoutMs);
|