@sudobility/testomniac_runner_service 0.1.74 → 0.1.76
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/analyzer/page-analyzer/generators/login.d.ts +15 -0
- package/dist/analyzer/page-analyzer/generators/login.d.ts.map +1 -0
- package/dist/analyzer/page-analyzer/generators/login.js +209 -0
- package/dist/analyzer/page-analyzer/generators/login.js.map +1 -0
- package/dist/analyzer/page-analyzer/index.d.ts.map +1 -1
- package/dist/analyzer/page-analyzer/index.js +16 -0
- package/dist/analyzer/page-analyzer/index.js.map +1 -1
- package/dist/analyzer/page-analyzer/types.d.ts +5 -0
- package/dist/analyzer/page-analyzer/types.d.ts.map +1 -1
- package/dist/api/client.d.ts +11 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +6 -0
- package/dist/api/client.js.map +1 -1
- package/dist/crawler/link-extractor.d.ts +1 -1
- package/dist/crawler/link-extractor.d.ts.map +1 -1
- package/dist/crawler/link-extractor.js +4 -1
- package/dist/crawler/link-extractor.js.map +1 -1
- package/dist/crawler/scope-checker.d.ts +6 -0
- package/dist/crawler/scope-checker.d.ts.map +1 -0
- package/dist/crawler/scope-checker.js +14 -0
- package/dist/crawler/scope-checker.js.map +1 -0
- package/dist/expertise/content-expertise.d.ts +3 -0
- package/dist/expertise/content-expertise.d.ts.map +1 -1
- package/dist/expertise/content-expertise.js +95 -0
- package/dist/expertise/content-expertise.js.map +1 -1
- package/dist/expertise/ui-expertise.d.ts +2 -0
- package/dist/expertise/ui-expertise.d.ts.map +1 -1
- package/dist/expertise/ui-expertise.js +77 -0
- package/dist/expertise/ui-expertise.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/login-manager.d.ts +62 -0
- package/dist/orchestrator/login-manager.d.ts.map +1 -0
- package/dist/orchestrator/login-manager.js +241 -0
- package/dist/orchestrator/login-manager.js.map +1 -0
- package/dist/orchestrator/runner.d.ts.map +1 -1
- package/dist/orchestrator/runner.js +49 -1
- package/dist/orchestrator/runner.js.map +1 -1
- package/dist/orchestrator/sso-handler.d.ts +29 -0
- package/dist/orchestrator/sso-handler.d.ts.map +1 -0
- package/dist/orchestrator/sso-handler.js +223 -0
- package/dist/orchestrator/sso-handler.js.map +1 -0
- package/dist/orchestrator/test-interaction-executor.d.ts +1 -1
- package/dist/orchestrator/test-interaction-executor.d.ts.map +1 -1
- package/dist/orchestrator/test-interaction-executor.js +62 -1
- package/dist/orchestrator/test-interaction-executor.js.map +1 -1
- package/dist/orchestrator/types.d.ts +5 -0
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/scanner/login-detector.d.ts +25 -0
- package/dist/scanner/login-detector.d.ts.map +1 -0
- package/dist/scanner/login-detector.js +232 -0
- package/dist/scanner/login-detector.js.map +1 -0
- package/dist/scanner/page-health-evaluator.d.ts +16 -0
- package/dist/scanner/page-health-evaluator.d.ts.map +1 -0
- package/dist/scanner/page-health-evaluator.js +222 -0
- package/dist/scanner/page-health-evaluator.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Constants
|
|
3
|
+
// =============================================================================
|
|
4
|
+
const LOGIN_URL_PATTERNS = [
|
|
5
|
+
/\/login\b/i,
|
|
6
|
+
/\/signin\b/i,
|
|
7
|
+
/\/sign-in\b/i,
|
|
8
|
+
/\/auth\b/i,
|
|
9
|
+
/\/sso\b/i,
|
|
10
|
+
/\/authenticate\b/i,
|
|
11
|
+
/\/log-in\b/i,
|
|
12
|
+
/\/account\/login/i,
|
|
13
|
+
];
|
|
14
|
+
const SSO_PROVIDER_PATTERNS = [
|
|
15
|
+
{
|
|
16
|
+
provider: "google",
|
|
17
|
+
textPatterns: [
|
|
18
|
+
/sign\s*in\s*with\s*google/i,
|
|
19
|
+
/continue\s*with\s*google/i,
|
|
20
|
+
/log\s*in\s*with\s*google/i,
|
|
21
|
+
/google\s*sign[\s-]*in/i,
|
|
22
|
+
],
|
|
23
|
+
hrefPatterns: [/accounts\.google\.com/i, /googleapis\.com\/auth/i],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
provider: "apple",
|
|
27
|
+
textPatterns: [/sign\s*in\s*with\s*apple/i, /continue\s*with\s*apple/i],
|
|
28
|
+
hrefPatterns: [/appleid\.apple\.com/i],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
provider: "microsoft",
|
|
32
|
+
textPatterns: [
|
|
33
|
+
/sign\s*in\s*with\s*microsoft/i,
|
|
34
|
+
/continue\s*with\s*microsoft/i,
|
|
35
|
+
],
|
|
36
|
+
hrefPatterns: [/login\.microsoftonline\.com/i, /login\.live\.com/i],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
provider: "twitter",
|
|
40
|
+
textPatterns: [
|
|
41
|
+
/sign\s*in\s*with\s*twitter/i,
|
|
42
|
+
/continue\s*with\s*twitter/i,
|
|
43
|
+
/sign\s*in\s*with\s*x\b/i,
|
|
44
|
+
],
|
|
45
|
+
hrefPatterns: [/api\.twitter\.com\/oauth/i, /twitter\.com\/i\/oauth/i],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
provider: "facebook",
|
|
49
|
+
textPatterns: [
|
|
50
|
+
/sign\s*in\s*with\s*facebook/i,
|
|
51
|
+
/continue\s*with\s*facebook/i,
|
|
52
|
+
/log\s*in\s*with\s*facebook/i,
|
|
53
|
+
],
|
|
54
|
+
hrefPatterns: [/facebook\.com\/v\d+.*\/dialog\/oauth/i],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
provider: "github",
|
|
58
|
+
textPatterns: [/sign\s*in\s*with\s*github/i, /continue\s*with\s*github/i],
|
|
59
|
+
hrefPatterns: [/github\.com\/login\/oauth/i],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
provider: "linkedin",
|
|
63
|
+
textPatterns: [
|
|
64
|
+
/sign\s*in\s*with\s*linkedin/i,
|
|
65
|
+
/continue\s*with\s*linkedin/i,
|
|
66
|
+
],
|
|
67
|
+
hrefPatterns: [/linkedin\.com\/oauth/i],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
provider: "okta",
|
|
71
|
+
textPatterns: [/sign\s*in\s*with\s*okta/i],
|
|
72
|
+
hrefPatterns: [/\.okta\.com/i, /\.oktapreview\.com/i],
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
// =============================================================================
|
|
76
|
+
// Detection
|
|
77
|
+
// =============================================================================
|
|
78
|
+
function matchesUrlPattern(url) {
|
|
79
|
+
return LOGIN_URL_PATTERNS.some(pattern => pattern.test(url));
|
|
80
|
+
}
|
|
81
|
+
function isLoginForm(form) {
|
|
82
|
+
const hasPassword = form.fields.some(f => f.type === "password");
|
|
83
|
+
const hasEmailOrUsername = form.fields.some(f => f.type === "email" ||
|
|
84
|
+
f.name?.toLowerCase().includes("email") ||
|
|
85
|
+
f.name?.toLowerCase().includes("user") ||
|
|
86
|
+
f.name?.toLowerCase().includes("login") ||
|
|
87
|
+
f.placeholder?.toLowerCase().includes("email") ||
|
|
88
|
+
f.placeholder?.toLowerCase().includes("username"));
|
|
89
|
+
const fieldCount = form.fields.filter(f => f.type !== "hidden" && f.type !== "submit").length;
|
|
90
|
+
return hasPassword && hasEmailOrUsername && fieldCount <= 4;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Detect SSO buttons on the current page by evaluating the DOM.
|
|
94
|
+
*/
|
|
95
|
+
async function detectSSOButtons(adapter) {
|
|
96
|
+
const buttonData = await adapter.evaluate(() => {
|
|
97
|
+
const results = [];
|
|
98
|
+
const candidates = document.querySelectorAll('a, button, [role="button"], [type="submit"]');
|
|
99
|
+
candidates.forEach((el, idx) => {
|
|
100
|
+
const text = el.textContent?.trim().replace(/\s+/g, " ").slice(0, 200);
|
|
101
|
+
const href = el.getAttribute("href") || "";
|
|
102
|
+
const id = el.id ? `#${el.id}` : "";
|
|
103
|
+
const cls = el.className
|
|
104
|
+
? `.${String(el.className).split(" ").filter(Boolean).slice(0, 2).join(".")}`
|
|
105
|
+
: "";
|
|
106
|
+
const tag = el.tagName.toLowerCase();
|
|
107
|
+
const selector = id || cls ? `${tag}${id}${cls}` : `${tag}:nth-of-type(${idx + 1})`;
|
|
108
|
+
if (text || href) {
|
|
109
|
+
results.push({ text: text || "", href, selector });
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return results;
|
|
113
|
+
});
|
|
114
|
+
const ssoButtons = [];
|
|
115
|
+
for (const btn of buttonData) {
|
|
116
|
+
for (const providerDef of SSO_PROVIDER_PATTERNS) {
|
|
117
|
+
const textMatch = providerDef.textPatterns.some(p => p.test(btn.text));
|
|
118
|
+
const hrefMatch = providerDef.hrefPatterns.some(p => p.test(btn.href));
|
|
119
|
+
if (textMatch || hrefMatch) {
|
|
120
|
+
ssoButtons.push({
|
|
121
|
+
provider: providerDef.provider,
|
|
122
|
+
selector: btn.selector,
|
|
123
|
+
label: btn.text.slice(0, 100),
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return ssoButtons;
|
|
130
|
+
}
|
|
131
|
+
async function detectLoginHeadings(adapter) {
|
|
132
|
+
return adapter.evaluate(() => {
|
|
133
|
+
const headings = Array.from(document.querySelectorAll("h1, h2, h3"));
|
|
134
|
+
const patterns = [
|
|
135
|
+
/^sign\s*in$/i,
|
|
136
|
+
/^log\s*in$/i,
|
|
137
|
+
/^login$/i,
|
|
138
|
+
/^welcome\s*back$/i,
|
|
139
|
+
/^sign\s*in\s*to/i,
|
|
140
|
+
/^log\s*in\s*to/i,
|
|
141
|
+
];
|
|
142
|
+
for (const h of headings) {
|
|
143
|
+
const text = h.textContent?.trim() ?? "";
|
|
144
|
+
if (patterns.some(p => p.test(text)))
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Detect whether the current page is a login page using multiple heuristics.
|
|
152
|
+
*/
|
|
153
|
+
export async function detectLoginPage(adapter, currentUrl, forms) {
|
|
154
|
+
const signals = [];
|
|
155
|
+
let loginForm = null;
|
|
156
|
+
const ssoButtons = [];
|
|
157
|
+
// 1. URL pattern check
|
|
158
|
+
if (matchesUrlPattern(currentUrl)) {
|
|
159
|
+
signals.push("url_pattern");
|
|
160
|
+
}
|
|
161
|
+
// 2. Password field check
|
|
162
|
+
const hasPasswordField = await adapter.evaluate(() => {
|
|
163
|
+
const fields = Array.from(document.querySelectorAll('input[type="password"]'));
|
|
164
|
+
for (const f of fields) {
|
|
165
|
+
const el = f;
|
|
166
|
+
if (el.offsetParent !== null || el.offsetWidth > 0)
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
});
|
|
171
|
+
if (hasPasswordField) {
|
|
172
|
+
signals.push("password_field");
|
|
173
|
+
}
|
|
174
|
+
// 3. Email + password form check
|
|
175
|
+
for (const form of forms) {
|
|
176
|
+
if (isLoginForm(form)) {
|
|
177
|
+
signals.push("email_password_form");
|
|
178
|
+
loginForm = form;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 4. SSO button check
|
|
183
|
+
const detectedSSO = await detectSSOButtons(adapter);
|
|
184
|
+
if (detectedSSO.length > 0) {
|
|
185
|
+
signals.push("sso_button");
|
|
186
|
+
ssoButtons.push(...detectedSSO);
|
|
187
|
+
}
|
|
188
|
+
// 5. Login heading check
|
|
189
|
+
const hasLoginHeading = await detectLoginHeadings(adapter);
|
|
190
|
+
if (hasLoginHeading) {
|
|
191
|
+
signals.push("login_heading");
|
|
192
|
+
}
|
|
193
|
+
// Determine confidence
|
|
194
|
+
let confidence = "low";
|
|
195
|
+
const hasFormSignal = signals.includes("email_password_form") ||
|
|
196
|
+
signals.includes("password_field");
|
|
197
|
+
const hasUrlSignal = signals.includes("url_pattern");
|
|
198
|
+
const hasSSOSignal = signals.includes("sso_button");
|
|
199
|
+
if (hasFormSignal && hasUrlSignal) {
|
|
200
|
+
confidence = "high";
|
|
201
|
+
}
|
|
202
|
+
else if (hasFormSignal || (hasUrlSignal && hasSSOSignal)) {
|
|
203
|
+
confidence = "medium";
|
|
204
|
+
}
|
|
205
|
+
const isLoginPage = confidence === "high" ||
|
|
206
|
+
confidence === "medium" ||
|
|
207
|
+
(signals.length >= 2 && confidence === "low");
|
|
208
|
+
return {
|
|
209
|
+
isLoginPage,
|
|
210
|
+
confidence,
|
|
211
|
+
signals,
|
|
212
|
+
loginForm,
|
|
213
|
+
ssoButtons,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Check if a URL matches the explicit login URL or known auth URL patterns.
|
|
218
|
+
*/
|
|
219
|
+
export function isLoginUrl(url, explicitLoginUrl) {
|
|
220
|
+
if (explicitLoginUrl) {
|
|
221
|
+
try {
|
|
222
|
+
const current = new URL(url);
|
|
223
|
+
const login = new URL(explicitLoginUrl, url);
|
|
224
|
+
return (current.origin === login.origin && current.pathname === login.pathname);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
return url.includes(explicitLoginUrl);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return matchesUrlPattern(url);
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=login-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-detector.js","sourceRoot":"","sources":["../../src/scanner/login-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { BrowserAdapter } from "../adapter";
|
|
2
|
+
/**
|
|
3
|
+
* A page health issue found during browser-side evaluation.
|
|
4
|
+
*/
|
|
5
|
+
export interface PageHealthIssue {
|
|
6
|
+
type: "broken_image" | "element_overlap" | "dead_social_button" | "broken_link_pattern" | "cart_math_error" | "grammar_error" | "defunct_service" | "missing_price" | "inconsistent_grid";
|
|
7
|
+
severity: "error" | "warning";
|
|
8
|
+
title: string;
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Run browser-side page health checks that require DOM evaluation.
|
|
13
|
+
* Returns an array of issues found on the current page.
|
|
14
|
+
*/
|
|
15
|
+
export declare function evaluatePageHealth(adapter: BrowserAdapter): Promise<PageHealthIssue[]>;
|
|
16
|
+
//# sourceMappingURL=page-health-evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-health-evaluator.d.ts","sourceRoot":"","sources":["../../src/scanner/page-health-evaluator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EACA,cAAc,GACd,iBAAiB,GACjB,oBAAoB,GACpB,qBAAqB,GACrB,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,mBAAmB,CAAC;IACxB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,EAAE,CAAC,CAmQ5B"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run browser-side page health checks that require DOM evaluation.
|
|
3
|
+
* Returns an array of issues found on the current page.
|
|
4
|
+
*/
|
|
5
|
+
export async function evaluatePageHealth(adapter) {
|
|
6
|
+
const issues = [];
|
|
7
|
+
const results = await adapter.evaluate(() => {
|
|
8
|
+
const found = [];
|
|
9
|
+
// =========================================================================
|
|
10
|
+
// 1. Broken images — check naturalWidth for loaded images
|
|
11
|
+
// =========================================================================
|
|
12
|
+
const images = Array.from(document.querySelectorAll("img"));
|
|
13
|
+
const brokenImages = [];
|
|
14
|
+
for (const img of images) {
|
|
15
|
+
if (img.complete &&
|
|
16
|
+
img.naturalWidth === 0 &&
|
|
17
|
+
img.src &&
|
|
18
|
+
img.offsetParent !== null) {
|
|
19
|
+
const alt = img.alt || img.src.split("/").pop() || "unknown";
|
|
20
|
+
brokenImages.push(alt);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (brokenImages.length > 0) {
|
|
24
|
+
found.push({
|
|
25
|
+
type: "broken_image",
|
|
26
|
+
severity: "error",
|
|
27
|
+
title: `${brokenImages.length} broken image(s) detected`,
|
|
28
|
+
description: `Images that failed to load: ${brokenImages.slice(0, 5).join(", ")}${brokenImages.length > 5 ? ` and ${brokenImages.length - 5} more` : ""}`,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
// =========================================================================
|
|
32
|
+
// 2. Element overlap — check if interactive elements are obscured
|
|
33
|
+
// =========================================================================
|
|
34
|
+
const interactiveSelectors = "a[href], button, input, select, textarea, [role='button']";
|
|
35
|
+
const interactiveEls = Array.from(document.querySelectorAll(interactiveSelectors));
|
|
36
|
+
const overlappedElements = [];
|
|
37
|
+
for (const el of interactiveEls.slice(0, 50)) {
|
|
38
|
+
const rect = el.getBoundingClientRect();
|
|
39
|
+
if (rect.width === 0 || rect.height === 0)
|
|
40
|
+
continue;
|
|
41
|
+
if (rect.top < 0 || rect.left < 0)
|
|
42
|
+
continue;
|
|
43
|
+
const cx = rect.left + rect.width / 2;
|
|
44
|
+
const cy = rect.top + rect.height / 2;
|
|
45
|
+
const topEl = document.elementFromPoint(cx, cy);
|
|
46
|
+
if (topEl &&
|
|
47
|
+
topEl !== el &&
|
|
48
|
+
!el.contains(topEl) &&
|
|
49
|
+
!topEl.closest(interactiveSelectors)?.contains(el)) {
|
|
50
|
+
const elDesc = el.textContent?.trim().slice(0, 40) || el.tagName;
|
|
51
|
+
const blockDesc = topEl.tagName +
|
|
52
|
+
(topEl.className ? "." + String(topEl.className).split(" ")[0] : "");
|
|
53
|
+
overlappedElements.push(`"${elDesc}" obscured by <${blockDesc}>`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (overlappedElements.length > 0) {
|
|
57
|
+
found.push({
|
|
58
|
+
type: "element_overlap",
|
|
59
|
+
severity: "error",
|
|
60
|
+
title: `${overlappedElements.length} interactive element(s) obscured by overlapping content`,
|
|
61
|
+
description: overlappedElements.slice(0, 3).join("; "),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// =========================================================================
|
|
65
|
+
// 3. Dead social share buttons — icons/buttons without proper links
|
|
66
|
+
// =========================================================================
|
|
67
|
+
const socialKeywords = [
|
|
68
|
+
"facebook",
|
|
69
|
+
"twitter",
|
|
70
|
+
"linkedin",
|
|
71
|
+
"pinterest",
|
|
72
|
+
"email",
|
|
73
|
+
"share",
|
|
74
|
+
"myspace",
|
|
75
|
+
"whatsapp",
|
|
76
|
+
];
|
|
77
|
+
const socialEls = Array.from(document.querySelectorAll('[class*="social"], [class*="share"]'));
|
|
78
|
+
const deadSocial = [];
|
|
79
|
+
for (const el of socialEls) {
|
|
80
|
+
const cls = el.className.toLowerCase();
|
|
81
|
+
if (!socialKeywords.some(k => cls.includes(k)))
|
|
82
|
+
continue;
|
|
83
|
+
const isLink = el.tagName === "A" &&
|
|
84
|
+
el.getAttribute("href") &&
|
|
85
|
+
el.getAttribute("href") !== "#";
|
|
86
|
+
const hasLinkChild = !!el.querySelector('a[href]:not([href="#"])');
|
|
87
|
+
const hasOnclick = !!el.getAttribute("onclick");
|
|
88
|
+
if (!isLink && !hasLinkChild && !hasOnclick) {
|
|
89
|
+
const name = socialKeywords.find(k => cls.includes(k)) || "unknown";
|
|
90
|
+
deadSocial.push(name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (deadSocial.length > 0) {
|
|
94
|
+
found.push({
|
|
95
|
+
type: "dead_social_button",
|
|
96
|
+
severity: "warning",
|
|
97
|
+
title: `${deadSocial.length} social share button(s) are non-functional`,
|
|
98
|
+
description: `Non-clickable social buttons: ${deadSocial.join(", ")}`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// =========================================================================
|
|
102
|
+
// 4. Cart math validation — check subtotal + shipping = grand total
|
|
103
|
+
// =========================================================================
|
|
104
|
+
const pageText = document.body?.innerText || "";
|
|
105
|
+
const subtotalMatch = pageText.match(/(?:sub\s*total|cart\s*sub)[^\n$]*?\$\s?([\d,.]+)/i);
|
|
106
|
+
const shippingMatch = pageText.match(/shipping[^\n$]*?\$\s?([\d,.]+)/i);
|
|
107
|
+
const grandTotalMatch = pageText.match(/(?:grand\s*total|order\s*total)[^\n$]*?\$\s?([\d,.]+)/i);
|
|
108
|
+
if (subtotalMatch && shippingMatch && grandTotalMatch) {
|
|
109
|
+
const subtotal = parseFloat(subtotalMatch[1].replace(",", ""));
|
|
110
|
+
const shipping = parseFloat(shippingMatch[1].replace(",", ""));
|
|
111
|
+
const grandTotal = parseFloat(grandTotalMatch[1].replace(",", ""));
|
|
112
|
+
const expected = Math.round((subtotal + shipping) * 100) / 100;
|
|
113
|
+
if (Math.abs(grandTotal - expected) > 0.01) {
|
|
114
|
+
found.push({
|
|
115
|
+
type: "cart_math_error",
|
|
116
|
+
severity: "error",
|
|
117
|
+
title: "Cart grand total does not match subtotal + shipping",
|
|
118
|
+
description: `Subtotal ($${subtotal.toFixed(2)}) + Shipping ($${shipping.toFixed(2)}) = $${expected.toFixed(2)}, but Grand Total shows $${grandTotal.toFixed(2)}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// =========================================================================
|
|
123
|
+
// 5. Grammar: singular/plural mismatch (e.g., "1 results")
|
|
124
|
+
// =========================================================================
|
|
125
|
+
const grammarPatterns = [
|
|
126
|
+
{ pattern: /\b1\s+results\b/i, fix: '"1 result"' },
|
|
127
|
+
{ pattern: /\b1\s+items\b/i, fix: '"1 item"' },
|
|
128
|
+
{ pattern: /\b1\s+products\b/i, fix: '"1 product"' },
|
|
129
|
+
{ pattern: /\b0\s+result\b(?!s)/i, fix: '"0 results"' },
|
|
130
|
+
];
|
|
131
|
+
for (const { pattern, fix } of grammarPatterns) {
|
|
132
|
+
const match = pageText.match(pattern);
|
|
133
|
+
if (match) {
|
|
134
|
+
found.push({
|
|
135
|
+
type: "grammar_error",
|
|
136
|
+
severity: "warning",
|
|
137
|
+
title: `Grammar error: "${match[0]}"`,
|
|
138
|
+
description: `Should be ${fix} — singular/plural mismatch`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// =========================================================================
|
|
143
|
+
// 6. Defunct service links (MySpace, Google+, etc.)
|
|
144
|
+
// =========================================================================
|
|
145
|
+
const defunctServices = [
|
|
146
|
+
{ pattern: /myspace\.com|class.*myspace/i, name: "MySpace" },
|
|
147
|
+
{ pattern: /plus\.google\.com/i, name: "Google+" },
|
|
148
|
+
{ pattern: /vine\.co(?!mcast)/i, name: "Vine" },
|
|
149
|
+
];
|
|
150
|
+
const allLinks = Array.from(document.querySelectorAll("a[href], [class]"));
|
|
151
|
+
for (const { pattern, name } of defunctServices) {
|
|
152
|
+
for (const el of allLinks) {
|
|
153
|
+
const href = el.getAttribute("href") || "";
|
|
154
|
+
const cls = el.className || "";
|
|
155
|
+
if (pattern.test(href) || pattern.test(cls)) {
|
|
156
|
+
found.push({
|
|
157
|
+
type: "defunct_service",
|
|
158
|
+
severity: "warning",
|
|
159
|
+
title: `Link to defunct service: ${name}`,
|
|
160
|
+
description: `Page contains a link/reference to ${name}, which is no longer operational`,
|
|
161
|
+
});
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// =========================================================================
|
|
167
|
+
// 7. Missing product price — product page without visible price
|
|
168
|
+
// =========================================================================
|
|
169
|
+
const hasProductIndicators = !!document.querySelector('[class*="product_details"], [class*="ec_details"], .product-details');
|
|
170
|
+
const hasAddToCart = !!document.querySelector('[class*="addtocart"], .add-to-cart, [class*="add_to_cart"]');
|
|
171
|
+
const hasPriceElement = !!document.querySelector('[class*="price"]:not([class*="price_filter"])');
|
|
172
|
+
const hasLoginForPricing = /login\s*for\s*pricing/i.test(pageText);
|
|
173
|
+
if (hasProductIndicators && !hasPriceElement && !hasAddToCart) {
|
|
174
|
+
found.push({
|
|
175
|
+
type: "missing_price",
|
|
176
|
+
severity: "error",
|
|
177
|
+
title: "Product page missing price and add-to-cart",
|
|
178
|
+
description: "Product detail page detected but no price or add-to-cart button is visible",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (hasLoginForPricing) {
|
|
182
|
+
found.push({
|
|
183
|
+
type: "missing_price",
|
|
184
|
+
severity: "warning",
|
|
185
|
+
title: "Product price hidden behind login",
|
|
186
|
+
description: '"Login for Pricing" shown instead of product price — public visitors cannot see the price',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// =========================================================================
|
|
190
|
+
// 8. Grid/layout inconsistency — product grid items with wildly different heights
|
|
191
|
+
// =========================================================================
|
|
192
|
+
const gridItems = document.querySelectorAll('[class*="product_li"], .product-card, [class*="product-item"]');
|
|
193
|
+
if (gridItems.length >= 3) {
|
|
194
|
+
const heights = Array.from(gridItems)
|
|
195
|
+
.map(el => el.getBoundingClientRect().height)
|
|
196
|
+
.filter(h => h > 0);
|
|
197
|
+
if (heights.length >= 3) {
|
|
198
|
+
const avgHeight = heights.reduce((a, b) => a + b, 0) / heights.length;
|
|
199
|
+
const outliers = heights.filter(h => Math.abs(h - avgHeight) > avgHeight * 0.5);
|
|
200
|
+
if (outliers.length > 0) {
|
|
201
|
+
found.push({
|
|
202
|
+
type: "inconsistent_grid",
|
|
203
|
+
severity: "warning",
|
|
204
|
+
title: `Product grid layout has ${outliers.length} inconsistently sized item(s)`,
|
|
205
|
+
description: `Average item height is ${Math.round(avgHeight)}px but ${outliers.length} item(s) deviate by more than 50%`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return found;
|
|
211
|
+
});
|
|
212
|
+
for (const r of results) {
|
|
213
|
+
issues.push({
|
|
214
|
+
type: r.type,
|
|
215
|
+
severity: r.severity,
|
|
216
|
+
title: r.title,
|
|
217
|
+
description: r.description,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return issues;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=page-health-evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-health-evaluator.js","sourceRoot":"","sources":["../../src/scanner/page-health-evaluator.ts"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAuB;IAEvB,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;QAC1C,MAAM,KAAK,GAKN,EAAE,CAAC;QAER,4EAA4E;QAC5E,0DAA0D;QAC1D,4EAA4E;QAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5D,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,IACE,GAAG,CAAC,QAAQ;gBACZ,GAAG,CAAC,YAAY,KAAK,CAAC;gBACtB,GAAG,CAAC,GAAG;gBACP,GAAG,CAAC,YAAY,KAAK,IAAI,EACzB,CAAC;gBACD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,SAAS,CAAC;gBAC7D,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,GAAG,YAAY,CAAC,MAAM,2BAA2B;gBACxD,WAAW,EAAE,+BAA+B,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,YAAY,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;aAC1J,CAAC,CAAC;QACL,CAAC;QAED,4EAA4E;QAC5E,kEAAkE;QAClE,4EAA4E;QAC5E,MAAM,oBAAoB,GACxB,2DAA2D,CAAC;QAC9D,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAC/B,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAChD,CAAC;QACF,MAAM,kBAAkB,GAAa,EAAE,CAAC;QACxC,KAAK,MAAM,EAAE,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACpD,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC;gBAAE,SAAS;YAC5C,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;YACtC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAChD,IACE,KAAK;gBACL,KAAK,KAAK,EAAE;gBACZ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;gBACnB,CAAC,KAAK,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,EAClD,CAAC;gBACD,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC;gBACjE,MAAM,SAAS,GACb,KAAK,CAAC,OAAO;oBACb,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvE,kBAAkB,CAAC,IAAI,CAAC,IAAI,MAAM,kBAAkB,SAAS,GAAG,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QACD,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,iBAAiB;gBACvB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,GAAG,kBAAkB,CAAC,MAAM,yDAAyD;gBAC5F,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;aACvD,CAAC,CAAC;QACL,CAAC;QAED,4EAA4E;QAC5E,oEAAoE;QACpE,4EAA4E;QAC5E,MAAM,cAAc,GAAG;YACrB,UAAU;YACV,SAAS;YACT,UAAU;YACV,WAAW;YACX,OAAO;YACP,OAAO;YACP,SAAS;YACT,UAAU;SACX,CAAC;QACF,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAC1B,QAAQ,CAAC,gBAAgB,CAAC,qCAAqC,CAAC,CACjE,CAAC;QACF,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAAE,SAAS;YACzD,MAAM,MAAM,GACV,EAAE,CAAC,OAAO,KAAK,GAAG;gBAClB,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC;gBACvB,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC;YAClC,MAAM,YAAY,GAAG,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;YACnE,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAChD,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC5C,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;gBACpE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,GAAG,UAAU,CAAC,MAAM,4CAA4C;gBACvE,WAAW,EAAE,iCAAiC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aACtE,CAAC,CAAC;QACL,CAAC;QAED,4EAA4E;QAC5E,oEAAoE;QACpE,4EAA4E;QAC5E,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;QAChD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAClC,mDAAmD,CACpD,CAAC;QACF,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACxE,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CACpC,wDAAwD,CACzD,CAAC;QAEF,IAAI,aAAa,IAAI,aAAa,IAAI,eAAe,EAAE,CAAC;YACtD,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/D,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/D,MAAM,UAAU,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;YAC/D,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,CAAC;gBAC3C,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,iBAAiB;oBACvB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,qDAAqD;oBAC5D,WAAW,EAAE,cAAc,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;iBAClK,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,2DAA2D;QAC3D,4EAA4E;QAC5E,MAAM,eAAe,GAAG;YACtB,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,YAAY,EAAE;YAClD,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,EAAE;YAC9C,EAAE,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,aAAa,EAAE;YACpD,EAAE,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,aAAa,EAAE;SACxD,CAAC;QACF,KAAK,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,eAAe,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,KAAK,EAAE,CAAC;gBACV,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,eAAe;oBACrB,QAAQ,EAAE,SAAS;oBACnB,KAAK,EAAE,mBAAmB,KAAK,CAAC,CAAC,CAAC,GAAG;oBACrC,WAAW,EAAE,aAAa,GAAG,6BAA6B;iBAC3D,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,oDAAoD;QACpD,4EAA4E;QAC5E,MAAM,eAAe,GAAG;YACtB,EAAE,OAAO,EAAE,8BAA8B,EAAE,IAAI,EAAE,SAAS,EAAE;YAC5D,EAAE,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,SAAS,EAAE;YAClD,EAAE,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,EAAE;SAChD,CAAC;QACF,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC,CAAC;QAC3E,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,eAAe,EAAE,CAAC;YAChD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC3C,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC;gBAC/B,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5C,KAAK,CAAC,IAAI,CAAC;wBACT,IAAI,EAAE,iBAAiB;wBACvB,QAAQ,EAAE,SAAS;wBACnB,KAAK,EAAE,4BAA4B,IAAI,EAAE;wBACzC,WAAW,EAAE,qCAAqC,IAAI,kCAAkC;qBACzF,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,gEAAgE;QAChE,4EAA4E;QAC5E,MAAM,oBAAoB,GAAG,CAAC,CAAC,QAAQ,CAAC,aAAa,CACnD,qEAAqE,CACtE,CAAC;QACF,MAAM,YAAY,GAAG,CAAC,CAAC,QAAQ,CAAC,aAAa,CAC3C,4DAA4D,CAC7D,CAAC;QACF,MAAM,eAAe,GAAG,CAAC,CAAC,QAAQ,CAAC,aAAa,CAC9C,+CAA+C,CAChD,CAAC;QACF,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEnE,IAAI,oBAAoB,IAAI,CAAC,eAAe,IAAI,CAAC,YAAY,EAAE,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,eAAe;gBACrB,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,4CAA4C;gBACnD,WAAW,EACT,4EAA4E;aAC/E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,kBAAkB,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,eAAe;gBACrB,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,mCAAmC;gBAC1C,WAAW,EACT,2FAA2F;aAC9F,CAAC,CAAC;QACL,CAAC;QAED,4EAA4E;QAC5E,kFAAkF;QAClF,4EAA4E;QAC5E,MAAM,SAAS,GAAG,QAAQ,CAAC,gBAAgB,CACzC,+DAA+D,CAChE,CAAC;QACF,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;iBAClC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,EAAE,CAAC,MAAM,CAAC;iBAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtB,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;gBACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAC7B,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,GAAG,GAAG,CAC/C,CAAC;gBACF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,KAAK,CAAC,IAAI,CAAC;wBACT,IAAI,EAAE,mBAAmB;wBACzB,QAAQ,EAAE,SAAS;wBACnB,KAAK,EAAE,2BAA2B,QAAQ,CAAC,MAAM,+BAA+B;wBAChF,WAAW,EAAE,0BAA0B,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,QAAQ,CAAC,MAAM,mCAAmC;qBACzH,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,CAAC,CAAC,IAA+B;YACvC,QAAQ,EAAE,CAAC,CAAC,QAA+B;YAC3C,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sudobility/testomniac_runner_service",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.76",
|
|
4
4
|
"description": "Shared scanning logic for Testomniac scanner and Chrome extension",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"author": "Sudobility",
|
|
38
38
|
"license": "BUSL-1.1",
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@sudobility/testomniac_types": "^0.0.
|
|
40
|
+
"@sudobility/testomniac_types": "^0.0.56",
|
|
41
41
|
"openai": ">=6.0.0",
|
|
42
42
|
"react": ">=18.0.0"
|
|
43
43
|
},
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@eslint/js": "^9.38.0",
|
|
54
|
-
"@sudobility/testomniac_types": "^0.0.
|
|
54
|
+
"@sudobility/testomniac_types": "^0.0.56",
|
|
55
55
|
"@types/node": "^25.6.0",
|
|
56
56
|
"@types/react": "^19.2.0",
|
|
57
57
|
"@typescript-eslint/eslint-plugin": "^8.46.2",
|