webpeel 0.17.19 → 0.17.20
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/core/browser-fetch.d.ts.map +1 -1
- package/dist/core/browser-fetch.js +80 -225
- package/dist/core/browser-fetch.js.map +1 -1
- package/dist/server/openapi.yaml +648 -0
- package/dist/server/routes/screenshot.d.ts.map +1 -1
- package/dist/server/routes/screenshot.js +77 -130
- package/dist/server/routes/screenshot.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-fetch.d.ts","sourceRoot":"","sources":["../../src/core/browser-fetch.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"browser-fetch.d.ts","sourceRoot":"","sources":["../../src/core/browser-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -826,15 +826,25 @@ export async function browserFilmstrip(url, options = {}) {
|
|
|
826
826
|
activePagesCount--;
|
|
827
827
|
}
|
|
828
828
|
}
|
|
829
|
-
// ──
|
|
829
|
+
// ── withBrowserPage ───────────────────────────────────────────────────────────
|
|
830
830
|
/**
|
|
831
|
-
*
|
|
832
|
-
*
|
|
833
|
-
*
|
|
831
|
+
* Shared boilerplate for the 4 new screenshot functions:
|
|
832
|
+
* - Queue concurrency wait
|
|
833
|
+
* - Launch browser (stealth or normal)
|
|
834
|
+
* - Open a new page with viewport + userAgent
|
|
835
|
+
* - Apply stealth scripts
|
|
836
|
+
* - Set custom headers and cookies
|
|
837
|
+
* - Navigate to the URL (with error normalisation)
|
|
838
|
+
* - Wait optional extra time
|
|
839
|
+
* - Call `fn(page)` for the unique per-function logic
|
|
840
|
+
* - Always close the page and decrement the counter
|
|
841
|
+
*
|
|
842
|
+
* NOTE: Do NOT touch browserFetch / browserScreenshot / browserFilmstrip —
|
|
843
|
+
* they have slightly different pooling / keep-open logic.
|
|
834
844
|
*/
|
|
835
|
-
|
|
845
|
+
async function withBrowserPage(url, opts, fn) {
|
|
836
846
|
validateUrl(url);
|
|
837
|
-
const { width = 1440, height = 900,
|
|
847
|
+
const { width = 1440, height = 900, userAgent, headers, cookies, stealth = false, waitMs = 0, timeoutMs = 60000, } = opts;
|
|
838
848
|
const validatedUserAgent = userAgent ? validateUserAgent(userAgent) : getRandomUserAgent();
|
|
839
849
|
const queueStartTime = Date.now();
|
|
840
850
|
const QUEUE_TIMEOUT_MS = 30000;
|
|
@@ -865,7 +875,6 @@ export async function browserAudit(url, options = {}) {
|
|
|
865
875
|
});
|
|
866
876
|
await page.context().addCookies(parsedCookies);
|
|
867
877
|
}
|
|
868
|
-
await page.route('**/*', (route) => route.continue());
|
|
869
878
|
try {
|
|
870
879
|
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
|
|
871
880
|
}
|
|
@@ -879,6 +888,32 @@ export async function browserAudit(url, options = {}) {
|
|
|
879
888
|
}
|
|
880
889
|
if (waitMs > 0)
|
|
881
890
|
await page.waitForTimeout(waitMs);
|
|
891
|
+
const result = await fn(page);
|
|
892
|
+
const finalUrl = page.url();
|
|
893
|
+
return { result, finalUrl };
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError)
|
|
897
|
+
throw error;
|
|
898
|
+
if (error instanceof Error && error.message.includes('Timeout'))
|
|
899
|
+
throw new TimeoutError('Browser operation timed out');
|
|
900
|
+
throw new NetworkError(`Browser operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
901
|
+
}
|
|
902
|
+
finally {
|
|
903
|
+
if (page)
|
|
904
|
+
await page.close().catch(() => { });
|
|
905
|
+
activePagesCount--;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
// ── browserAudit ──────────────────────────────────────────────────────────────
|
|
909
|
+
/**
|
|
910
|
+
* Section-aware audit screenshots.
|
|
911
|
+
* Finds all elements matching a CSS selector and captures a viewport screenshot
|
|
912
|
+
* scrolled to each one. Returns one image buffer per matching element.
|
|
913
|
+
*/
|
|
914
|
+
export async function browserAudit(url, options = {}) {
|
|
915
|
+
const { width = 1440, height = 900, format = 'jpeg', quality = 80, selector = 'section', waitMs = 0, timeoutMs = 60000, userAgent, headers, cookies, stealth = false, scrollThrough = false, } = options;
|
|
916
|
+
const { result: frames, finalUrl } = await withBrowserPage(url, { width, height, userAgent, headers, cookies, stealth, waitMs, timeoutMs }, async (page) => {
|
|
882
917
|
// Scroll through to trigger lazy content
|
|
883
918
|
if (scrollThrough) {
|
|
884
919
|
const scrollHeight = await page.evaluate(() => document.body.scrollHeight);
|
|
@@ -909,7 +944,6 @@ export async function browserAudit(url, options = {}) {
|
|
|
909
944
|
const capturedFrames = [];
|
|
910
945
|
for (let i = 0; i < elements.length; i++) {
|
|
911
946
|
const el = elements[i];
|
|
912
|
-
// Scroll so the element is at the top of the viewport
|
|
913
947
|
await page.evaluate((y) => window.scrollTo({ top: y, behavior: 'instant' }), el.top);
|
|
914
948
|
await page.waitForTimeout(200);
|
|
915
949
|
const buf = await page.screenshot({
|
|
@@ -918,74 +952,18 @@ export async function browserAudit(url, options = {}) {
|
|
|
918
952
|
});
|
|
919
953
|
capturedFrames.push({ index: i, ...el, buffer: buf });
|
|
920
954
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}
|
|
924
|
-
catch (error) {
|
|
925
|
-
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError)
|
|
926
|
-
throw error;
|
|
927
|
-
if (error instanceof Error && error.message.includes('Timeout'))
|
|
928
|
-
throw new TimeoutError('Browser audit timed out');
|
|
929
|
-
throw new NetworkError(`Browser audit failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
930
|
-
}
|
|
931
|
-
finally {
|
|
932
|
-
if (page)
|
|
933
|
-
await page.close().catch(() => { });
|
|
934
|
-
activePagesCount--;
|
|
935
|
-
}
|
|
955
|
+
return capturedFrames;
|
|
956
|
+
});
|
|
957
|
+
return { frames, finalUrl };
|
|
936
958
|
}
|
|
937
959
|
// ── browserAnimationCapture ───────────────────────────────────────────────────
|
|
938
960
|
/**
|
|
939
961
|
* Capture N viewport screenshots at fixed intervals to record CSS animation states.
|
|
940
962
|
*/
|
|
941
963
|
export async function browserAnimationCapture(url, options = {}) {
|
|
942
|
-
validateUrl(url);
|
|
943
964
|
const { frames: frameCount = 6, intervalMs = 500, scrollTo, selector, width = 1440, height = 900, format = 'jpeg', quality = 80, waitMs = 0, timeoutMs = 60000, userAgent, headers, cookies, stealth = false, } = options;
|
|
944
965
|
const numFrames = Math.max(1, Math.min(30, frameCount));
|
|
945
|
-
const
|
|
946
|
-
const queueStartTime = Date.now();
|
|
947
|
-
const QUEUE_TIMEOUT_MS = 30000;
|
|
948
|
-
while (activePagesCount >= MAX_CONCURRENT_PAGES) {
|
|
949
|
-
if (Date.now() - queueStartTime > QUEUE_TIMEOUT_MS) {
|
|
950
|
-
throw new TimeoutError('Browser page queue timeout - too many concurrent requests');
|
|
951
|
-
}
|
|
952
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
953
|
-
}
|
|
954
|
-
activePagesCount++;
|
|
955
|
-
let page = null;
|
|
956
|
-
try {
|
|
957
|
-
const browser = stealth ? await getStealthBrowser() : await getBrowser();
|
|
958
|
-
page = await browser.newPage({
|
|
959
|
-
userAgent: validatedUserAgent,
|
|
960
|
-
viewport: { width, height },
|
|
961
|
-
});
|
|
962
|
-
await applyStealthScripts(page);
|
|
963
|
-
if (headers)
|
|
964
|
-
await page.setExtraHTTPHeaders(headers);
|
|
965
|
-
if (cookies && cookies.length > 0) {
|
|
966
|
-
const parsedCookies = cookies.map(cookie => {
|
|
967
|
-
const [nameValue] = cookie.split(';').map((s) => s.trim());
|
|
968
|
-
const [name, value] = nameValue.split('=');
|
|
969
|
-
if (!name || value === undefined)
|
|
970
|
-
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
971
|
-
return { name: name.trim(), value: value.trim(), url };
|
|
972
|
-
});
|
|
973
|
-
await page.context().addCookies(parsedCookies);
|
|
974
|
-
}
|
|
975
|
-
await page.route('**/*', (route) => route.continue());
|
|
976
|
-
try {
|
|
977
|
-
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
|
|
978
|
-
}
|
|
979
|
-
catch (gotoError) {
|
|
980
|
-
const msg = gotoError?.message || String(gotoError);
|
|
981
|
-
if (/timeout/i.test(msg))
|
|
982
|
-
throw new TimeoutError(`Page load timed out after ${timeoutMs}ms: ${url}`);
|
|
983
|
-
if (/net::ERR_/i.test(msg))
|
|
984
|
-
throw new NetworkError(`Browser network error: ${msg.match(/net::ERR_\w+/i)?.[0] || msg}`);
|
|
985
|
-
throw gotoError;
|
|
986
|
-
}
|
|
987
|
-
if (waitMs > 0)
|
|
988
|
-
await page.waitForTimeout(waitMs);
|
|
966
|
+
const { result: frames, finalUrl } = await withBrowserPage(url, { width, height, userAgent, headers, cookies, stealth, waitMs, timeoutMs }, async (page) => {
|
|
989
967
|
// Position the viewport
|
|
990
968
|
if (selector) {
|
|
991
969
|
await page.evaluate((sel) => {
|
|
@@ -1011,21 +989,9 @@ export async function browserAnimationCapture(url, options = {}) {
|
|
|
1011
989
|
await page.waitForTimeout(intervalMs);
|
|
1012
990
|
}
|
|
1013
991
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1017
|
-
catch (error) {
|
|
1018
|
-
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError)
|
|
1019
|
-
throw error;
|
|
1020
|
-
if (error instanceof Error && error.message.includes('Timeout'))
|
|
1021
|
-
throw new TimeoutError('Browser animation capture timed out');
|
|
1022
|
-
throw new NetworkError(`Browser animation capture failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1023
|
-
}
|
|
1024
|
-
finally {
|
|
1025
|
-
if (page)
|
|
1026
|
-
await page.close().catch(() => { });
|
|
1027
|
-
activePagesCount--;
|
|
1028
|
-
}
|
|
992
|
+
return capturedFrames;
|
|
993
|
+
});
|
|
994
|
+
return { frames, finalUrl };
|
|
1029
995
|
}
|
|
1030
996
|
// ── browserViewports ──────────────────────────────────────────────────────────
|
|
1031
997
|
/**
|
|
@@ -1033,57 +999,13 @@ export async function browserAnimationCapture(url, options = {}) {
|
|
|
1033
999
|
* Resizes the viewport between each capture.
|
|
1034
1000
|
*/
|
|
1035
1001
|
export async function browserViewports(url, options) {
|
|
1036
|
-
validateUrl(url);
|
|
1037
1002
|
const { viewports, fullPage = false, format = 'jpeg', quality = 80, waitMs = 0, timeoutMs = 90000, userAgent, headers, cookies, stealth = false, scrollThrough = false, } = options;
|
|
1038
1003
|
if (!viewports || viewports.length === 0) {
|
|
1039
1004
|
throw new WebPeelError('At least one viewport is required');
|
|
1040
1005
|
}
|
|
1041
|
-
|
|
1042
|
-
const
|
|
1043
|
-
const
|
|
1044
|
-
while (activePagesCount >= MAX_CONCURRENT_PAGES) {
|
|
1045
|
-
if (Date.now() - queueStartTime > QUEUE_TIMEOUT_MS) {
|
|
1046
|
-
throw new TimeoutError('Browser page queue timeout - too many concurrent requests');
|
|
1047
|
-
}
|
|
1048
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1049
|
-
}
|
|
1050
|
-
activePagesCount++;
|
|
1051
|
-
let page = null;
|
|
1052
|
-
try {
|
|
1053
|
-
const browser = stealth ? await getStealthBrowser() : await getBrowser();
|
|
1054
|
-
// Use first viewport to initialize
|
|
1055
|
-
const firstVp = viewports[0];
|
|
1056
|
-
page = await browser.newPage({
|
|
1057
|
-
userAgent: validatedUserAgent,
|
|
1058
|
-
viewport: { width: firstVp.width, height: firstVp.height },
|
|
1059
|
-
});
|
|
1060
|
-
await applyStealthScripts(page);
|
|
1061
|
-
if (headers)
|
|
1062
|
-
await page.setExtraHTTPHeaders(headers);
|
|
1063
|
-
if (cookies && cookies.length > 0) {
|
|
1064
|
-
const parsedCookies = cookies.map(cookie => {
|
|
1065
|
-
const [nameValue] = cookie.split(';').map((s) => s.trim());
|
|
1066
|
-
const [name, value] = nameValue.split('=');
|
|
1067
|
-
if (!name || value === undefined)
|
|
1068
|
-
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
1069
|
-
return { name: name.trim(), value: value.trim(), url };
|
|
1070
|
-
});
|
|
1071
|
-
await page.context().addCookies(parsedCookies);
|
|
1072
|
-
}
|
|
1073
|
-
await page.route('**/*', (route) => route.continue());
|
|
1074
|
-
try {
|
|
1075
|
-
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
|
|
1076
|
-
}
|
|
1077
|
-
catch (gotoError) {
|
|
1078
|
-
const msg = gotoError?.message || String(gotoError);
|
|
1079
|
-
if (/timeout/i.test(msg))
|
|
1080
|
-
throw new TimeoutError(`Page load timed out after ${timeoutMs}ms: ${url}`);
|
|
1081
|
-
if (/net::ERR_/i.test(msg))
|
|
1082
|
-
throw new NetworkError(`Browser network error: ${msg.match(/net::ERR_\w+/i)?.[0] || msg}`);
|
|
1083
|
-
throw gotoError;
|
|
1084
|
-
}
|
|
1085
|
-
if (waitMs > 0)
|
|
1086
|
-
await page.waitForTimeout(waitMs);
|
|
1006
|
+
// Use first viewport dimensions for initial page setup
|
|
1007
|
+
const firstVp = viewports[0];
|
|
1008
|
+
const { result: frames, finalUrl } = await withBrowserPage(url, { width: firstVp.width, height: firstVp.height, userAgent, headers, cookies, stealth, waitMs, timeoutMs }, async (page) => {
|
|
1087
1009
|
const capturedFrames = [];
|
|
1088
1010
|
for (const vp of viewports) {
|
|
1089
1011
|
const label = vp.label || `${vp.width}x${vp.height}`;
|
|
@@ -1107,78 +1029,22 @@ export async function browserViewports(url, options) {
|
|
|
1107
1029
|
});
|
|
1108
1030
|
capturedFrames.push({ width: vp.width, height: vp.height, label, buffer: buf });
|
|
1109
1031
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
}
|
|
1113
|
-
catch (error) {
|
|
1114
|
-
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError)
|
|
1115
|
-
throw error;
|
|
1116
|
-
if (error instanceof Error && error.message.includes('Timeout'))
|
|
1117
|
-
throw new TimeoutError('Browser viewports timed out');
|
|
1118
|
-
throw new NetworkError(`Browser viewports failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1119
|
-
}
|
|
1120
|
-
finally {
|
|
1121
|
-
if (page)
|
|
1122
|
-
await page.close().catch(() => { });
|
|
1123
|
-
activePagesCount--;
|
|
1124
|
-
}
|
|
1032
|
+
return capturedFrames;
|
|
1033
|
+
});
|
|
1034
|
+
return { frames, finalUrl };
|
|
1125
1035
|
}
|
|
1126
1036
|
/**
|
|
1127
1037
|
* Extract computed CSS values and validate against design rules.
|
|
1128
1038
|
* Returns structured JSON instead of pixel images.
|
|
1129
1039
|
*/
|
|
1130
1040
|
export async function browserDesignAudit(url, options = {}) {
|
|
1131
|
-
validateUrl(url);
|
|
1132
1041
|
const { rules = {}, selector = 'body', width = 1440, height = 900, waitMs = 0, timeoutMs = 60000, userAgent, headers, cookies, stealth = false, } = options;
|
|
1133
1042
|
const spacingGrid = rules.spacingGrid ?? 8;
|
|
1134
1043
|
const minTouchTarget = rules.minTouchTarget ?? 44;
|
|
1135
1044
|
const minContrast = rules.minContrast ?? 4.5;
|
|
1136
|
-
const
|
|
1137
|
-
const queueStartTime = Date.now();
|
|
1138
|
-
const QUEUE_TIMEOUT_MS = 30000;
|
|
1139
|
-
while (activePagesCount >= MAX_CONCURRENT_PAGES) {
|
|
1140
|
-
if (Date.now() - queueStartTime > QUEUE_TIMEOUT_MS) {
|
|
1141
|
-
throw new TimeoutError('Browser page queue timeout - too many concurrent requests');
|
|
1142
|
-
}
|
|
1143
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1144
|
-
}
|
|
1145
|
-
activePagesCount++;
|
|
1146
|
-
let page = null;
|
|
1147
|
-
try {
|
|
1148
|
-
const browser = stealth ? await getStealthBrowser() : await getBrowser();
|
|
1149
|
-
page = await browser.newPage({
|
|
1150
|
-
userAgent: validatedUserAgent,
|
|
1151
|
-
viewport: { width, height },
|
|
1152
|
-
});
|
|
1153
|
-
await applyStealthScripts(page);
|
|
1154
|
-
if (headers)
|
|
1155
|
-
await page.setExtraHTTPHeaders(headers);
|
|
1156
|
-
if (cookies && cookies.length > 0) {
|
|
1157
|
-
const parsedCookies = cookies.map(cookie => {
|
|
1158
|
-
const [nameValue] = cookie.split(';').map((s) => s.trim());
|
|
1159
|
-
const [name, value] = nameValue.split('=');
|
|
1160
|
-
if (!name || value === undefined)
|
|
1161
|
-
throw new WebPeelError(`Invalid cookie format: ${cookie}`);
|
|
1162
|
-
return { name: name.trim(), value: value.trim(), url };
|
|
1163
|
-
});
|
|
1164
|
-
await page.context().addCookies(parsedCookies);
|
|
1165
|
-
}
|
|
1166
|
-
await page.route('**/*', (route) => route.continue());
|
|
1167
|
-
try {
|
|
1168
|
-
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: timeoutMs });
|
|
1169
|
-
}
|
|
1170
|
-
catch (gotoError) {
|
|
1171
|
-
const msg = gotoError?.message || String(gotoError);
|
|
1172
|
-
if (/timeout/i.test(msg))
|
|
1173
|
-
throw new TimeoutError(`Page load timed out after ${timeoutMs}ms: ${url}`);
|
|
1174
|
-
if (/net::ERR_/i.test(msg))
|
|
1175
|
-
throw new NetworkError(`Browser network error: ${msg.match(/net::ERR_\w+/i)?.[0] || msg}`);
|
|
1176
|
-
throw gotoError;
|
|
1177
|
-
}
|
|
1178
|
-
if (waitMs > 0)
|
|
1179
|
-
await page.waitForTimeout(waitMs);
|
|
1045
|
+
const { result: auditData, finalUrl } = await withBrowserPage(url, { width, height, userAgent, headers, cookies, stealth, waitMs, timeoutMs }, async (page) => {
|
|
1180
1046
|
// Run design audit inside the browser
|
|
1181
|
-
|
|
1047
|
+
return page.evaluate((params) => {
|
|
1182
1048
|
const { sel, spacingGrid, minTouchTarget, minContrast } = params;
|
|
1183
1049
|
// --- Helpers ---
|
|
1184
1050
|
function parsePixels(val) {
|
|
@@ -1186,7 +1052,7 @@ export async function browserDesignAudit(url, options = {}) {
|
|
|
1186
1052
|
return isNaN(n) ? 0 : n;
|
|
1187
1053
|
}
|
|
1188
1054
|
function parseRgb(color) {
|
|
1189
|
-
const m = color.match(/rgba?\((
|
|
1055
|
+
const m = color.match(/rgba?\(([0-9]+),\s*([0-9]+),\s*([0-9]+)/);
|
|
1190
1056
|
if (!m)
|
|
1191
1057
|
return null;
|
|
1192
1058
|
return [parseInt(m[1]), parseInt(m[2]), parseInt(m[3])];
|
|
@@ -1273,7 +1139,7 @@ export async function browserDesignAudit(url, options = {}) {
|
|
|
1273
1139
|
touchTargetViolations.push({ element: label, width: Math.round(w), height: Math.round(h), minRequired: minTouchTarget });
|
|
1274
1140
|
}
|
|
1275
1141
|
}
|
|
1276
|
-
// Contrast
|
|
1142
|
+
// Contrast — Fix: skip near-identical colors (ratio ≤ 1.05) to avoid false positives
|
|
1277
1143
|
const textColor = style.color;
|
|
1278
1144
|
const bgColor = style.backgroundColor;
|
|
1279
1145
|
if (textColor && bgColor) {
|
|
@@ -1281,7 +1147,7 @@ export async function browserDesignAudit(url, options = {}) {
|
|
|
1281
1147
|
const bg = parseRgb(bgColor);
|
|
1282
1148
|
if (fg && bg) {
|
|
1283
1149
|
const ratio = contrastRatio(fg, bg);
|
|
1284
|
-
if (ratio
|
|
1150
|
+
if (ratio > 1.05 && ratio < minContrast) {
|
|
1285
1151
|
// Only flag elements with visible text content
|
|
1286
1152
|
const text = el.textContent?.trim() || '';
|
|
1287
1153
|
if (text.length > 0 && text.length < 200) {
|
|
@@ -1310,36 +1176,25 @@ export async function browserDesignAudit(url, options = {}) {
|
|
|
1310
1176
|
spacingScale: [...new Set(spacingScale)].slice(0, 30),
|
|
1311
1177
|
};
|
|
1312
1178
|
}, { sel: selector, spacingGrid, minTouchTarget, minContrast });
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
if (error instanceof BlockedError || error instanceof WebPeelError || error instanceof TimeoutError)
|
|
1334
|
-
throw error;
|
|
1335
|
-
if (error instanceof Error && error.message.includes('Timeout'))
|
|
1336
|
-
throw new TimeoutError('Browser design audit timed out');
|
|
1337
|
-
throw new NetworkError(`Browser design audit failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1338
|
-
}
|
|
1339
|
-
finally {
|
|
1340
|
-
if (page)
|
|
1341
|
-
await page.close().catch(() => { });
|
|
1342
|
-
activePagesCount--;
|
|
1343
|
-
}
|
|
1179
|
+
});
|
|
1180
|
+
// Weighted scoring: contrast failures are most serious (accessibility),
|
|
1181
|
+
// touch target issues affect usability, spacing is cosmetic.
|
|
1182
|
+
const contrastPenalty = auditData.contrastViolations.length * 5;
|
|
1183
|
+
const touchPenalty = auditData.touchTargetViolations.length * 3;
|
|
1184
|
+
const spacingPenalty = auditData.spacingViolations.length * 1;
|
|
1185
|
+
const totalPenalty = contrastPenalty + touchPenalty + spacingPenalty;
|
|
1186
|
+
const score = Math.max(0, Math.round(100 - Math.min(100, totalPenalty)));
|
|
1187
|
+
const parts = [];
|
|
1188
|
+
if (auditData.spacingViolations.length > 0)
|
|
1189
|
+
parts.push(`${auditData.spacingViolations.length} spacing violation(s)`);
|
|
1190
|
+
if (auditData.touchTargetViolations.length > 0)
|
|
1191
|
+
parts.push(`${auditData.touchTargetViolations.length} touch target violation(s)`);
|
|
1192
|
+
if (auditData.contrastViolations.length > 0)
|
|
1193
|
+
parts.push(`${auditData.contrastViolations.length} contrast violation(s)`);
|
|
1194
|
+
const summary = parts.length === 0
|
|
1195
|
+
? 'No design violations found.'
|
|
1196
|
+
: `Found: ${parts.join(', ')}.`;
|
|
1197
|
+
const audit = { score, summary, ...auditData };
|
|
1198
|
+
return { audit, finalUrl };
|
|
1344
1199
|
}
|
|
1345
1200
|
//# sourceMappingURL=browser-fetch.js.map
|