laxy-verify 1.2.0 → 1.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/dist/audit/broken-links.d.ts +21 -21
- package/dist/audit/broken-links.js +86 -86
- package/dist/auth.d.ts +11 -11
- package/dist/auth.js +222 -222
- package/dist/cli.js +830 -806
- package/dist/comment.d.ts +21 -21
- package/dist/comment.js +125 -125
- package/dist/crawler.d.ts +36 -36
- package/dist/crawler.js +357 -357
- package/dist/e2e.d.ts +49 -49
- package/dist/e2e.js +565 -565
- package/dist/entitlement.d.ts +11 -11
- package/dist/entitlement.js +90 -90
- package/dist/init.js +87 -87
- package/dist/multi-viewport.d.ts +31 -31
- package/dist/multi-viewport.js +298 -298
- package/dist/playwright-runner.d.ts +16 -16
- package/dist/playwright-runner.js +208 -208
- package/dist/report-markdown.d.ts +39 -39
- package/dist/report-markdown.js +386 -386
- package/dist/security-audit.d.ts +9 -9
- package/dist/security-audit.js +64 -64
- package/dist/serve.d.ts +13 -13
- package/dist/serve.js +196 -196
- package/dist/trend.d.ts +50 -50
- package/dist/trend.js +148 -148
- package/dist/verification-core/index.d.ts +3 -3
- package/dist/verification-core/index.js +19 -19
- package/dist/verification-core/report.d.ts +14 -14
- package/dist/verification-core/report.js +409 -409
- package/dist/verification-core/tier-policy.d.ts +13 -13
- package/dist/verification-core/tier-policy.js +60 -60
- package/dist/verification-core/types.d.ts +108 -108
- package/dist/verification-core/types.js +2 -2
- package/dist/visual-diff.d.ts +26 -26
- package/dist/visual-diff.js +178 -178
- package/package.json +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Broken-links audit.
|
|
3
|
-
* Uses the crawl result to find all internal links, then validates each
|
|
4
|
-
* with an HTTP HEAD/GET request. Links that return 4xx/5xx or timeout are
|
|
5
|
-
* reported as blockers.
|
|
6
|
-
*/
|
|
7
|
-
import { type CrawlResult } from "../crawler.js";
|
|
8
|
-
export interface BrokenLink {
|
|
9
|
-
url: string;
|
|
10
|
-
path: string;
|
|
11
|
-
status: number;
|
|
12
|
-
statusText: string;
|
|
13
|
-
severity: "critical" | "high";
|
|
14
|
-
}
|
|
15
|
-
export interface BrokenLinksResult {
|
|
16
|
-
brokenLinks: BrokenLink[];
|
|
17
|
-
checkedCount: number;
|
|
18
|
-
hasBrokenLinks: boolean;
|
|
19
|
-
summary: string;
|
|
20
|
-
}
|
|
21
|
-
export declare function auditBrokenLinks(crawlResult: CrawlResult, baseUrl: string, abortSignal?: AbortSignal): Promise<BrokenLinksResult>;
|
|
1
|
+
/**
|
|
2
|
+
* Broken-links audit.
|
|
3
|
+
* Uses the crawl result to find all internal links, then validates each
|
|
4
|
+
* with an HTTP HEAD/GET request. Links that return 4xx/5xx or timeout are
|
|
5
|
+
* reported as blockers.
|
|
6
|
+
*/
|
|
7
|
+
import { type CrawlResult } from "../crawler.js";
|
|
8
|
+
export interface BrokenLink {
|
|
9
|
+
url: string;
|
|
10
|
+
path: string;
|
|
11
|
+
status: number;
|
|
12
|
+
statusText: string;
|
|
13
|
+
severity: "critical" | "high";
|
|
14
|
+
}
|
|
15
|
+
export interface BrokenLinksResult {
|
|
16
|
+
brokenLinks: BrokenLink[];
|
|
17
|
+
checkedCount: number;
|
|
18
|
+
hasBrokenLinks: boolean;
|
|
19
|
+
summary: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function auditBrokenLinks(crawlResult: CrawlResult, baseUrl: string, abortSignal?: AbortSignal): Promise<BrokenLinksResult>;
|
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.auditBrokenLinks = auditBrokenLinks;
|
|
4
|
-
const TIMEOUT_MS = 5000;
|
|
5
|
-
const VALID_OK_STATUS = [200, 201, 202, 203, 204, 301, 302, 303, 307, 308];
|
|
6
|
-
function isSuccessStatus(n) {
|
|
7
|
-
return VALID_OK_STATUS.includes(n);
|
|
8
|
-
}
|
|
9
|
-
async function auditBrokenLinks(crawlResult, baseUrl, abortSignal) {
|
|
10
|
-
const origin = new URL(baseUrl).origin;
|
|
11
|
-
const allUrls = [];
|
|
12
|
-
for (const page of crawlResult.pages) {
|
|
13
|
-
for (const href of page.internalLinks) {
|
|
14
|
-
try {
|
|
15
|
-
const url = new URL(href, baseUrl).href;
|
|
16
|
-
if (!allUrls.includes(url))
|
|
17
|
-
allUrls.push(url);
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
// skip malformed URLs
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
const uniqueUrls = allUrls;
|
|
25
|
-
const brokenLinks = [];
|
|
26
|
-
await Promise.all(uniqueUrls.map(async (url) => {
|
|
27
|
-
if (abortSignal?.aborted)
|
|
28
|
-
return;
|
|
29
|
-
try {
|
|
30
|
-
const controller = new AbortController();
|
|
31
|
-
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
32
|
-
let status = 0;
|
|
33
|
-
let statusText = "";
|
|
34
|
-
try {
|
|
35
|
-
const res = await fetch(url, {
|
|
36
|
-
method: "HEAD",
|
|
37
|
-
redirect: "follow",
|
|
38
|
-
signal: controller.signal,
|
|
39
|
-
});
|
|
40
|
-
status = res.status;
|
|
41
|
-
statusText = res.statusText;
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
// Fall back to GET if HEAD is not allowed
|
|
45
|
-
const controller2 = new AbortController();
|
|
46
|
-
const timer2 = setTimeout(() => controller2.abort(), TIMEOUT_MS);
|
|
47
|
-
try {
|
|
48
|
-
const res = await fetch(url, {
|
|
49
|
-
method: "GET",
|
|
50
|
-
redirect: "follow",
|
|
51
|
-
signal: controller2.signal,
|
|
52
|
-
});
|
|
53
|
-
status = res.status;
|
|
54
|
-
statusText = res.statusText;
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
status = 0;
|
|
58
|
-
statusText = "timeout or network error";
|
|
59
|
-
}
|
|
60
|
-
clearTimeout(timer2);
|
|
61
|
-
}
|
|
62
|
-
clearTimeout(timer);
|
|
63
|
-
if (!isSuccessStatus(status)) {
|
|
64
|
-
const severity = status >= 500 ? "critical" : "high";
|
|
65
|
-
let path = url;
|
|
66
|
-
try {
|
|
67
|
-
path = new URL(url).pathname;
|
|
68
|
-
}
|
|
69
|
-
catch { }
|
|
70
|
-
brokenLinks.push({ url, path, status, statusText, severity });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// skip
|
|
75
|
-
}
|
|
76
|
-
}));
|
|
77
|
-
const summary = brokenLinks.length === 0
|
|
78
|
-
? `All ${uniqueUrls.length} links OK`
|
|
79
|
-
: `${brokenLinks.length} broken link(s) found`;
|
|
80
|
-
return {
|
|
81
|
-
brokenLinks,
|
|
82
|
-
checkedCount: uniqueUrls.length,
|
|
83
|
-
hasBrokenLinks: brokenLinks.length > 0,
|
|
84
|
-
summary,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.auditBrokenLinks = auditBrokenLinks;
|
|
4
|
+
const TIMEOUT_MS = 5000;
|
|
5
|
+
const VALID_OK_STATUS = [200, 201, 202, 203, 204, 301, 302, 303, 307, 308];
|
|
6
|
+
function isSuccessStatus(n) {
|
|
7
|
+
return VALID_OK_STATUS.includes(n);
|
|
8
|
+
}
|
|
9
|
+
async function auditBrokenLinks(crawlResult, baseUrl, abortSignal) {
|
|
10
|
+
const origin = new URL(baseUrl).origin;
|
|
11
|
+
const allUrls = [];
|
|
12
|
+
for (const page of crawlResult.pages) {
|
|
13
|
+
for (const href of page.internalLinks) {
|
|
14
|
+
try {
|
|
15
|
+
const url = new URL(href, baseUrl).href;
|
|
16
|
+
if (!allUrls.includes(url))
|
|
17
|
+
allUrls.push(url);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// skip malformed URLs
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const uniqueUrls = allUrls;
|
|
25
|
+
const brokenLinks = [];
|
|
26
|
+
await Promise.all(uniqueUrls.map(async (url) => {
|
|
27
|
+
if (abortSignal?.aborted)
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
32
|
+
let status = 0;
|
|
33
|
+
let statusText = "";
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(url, {
|
|
36
|
+
method: "HEAD",
|
|
37
|
+
redirect: "follow",
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
});
|
|
40
|
+
status = res.status;
|
|
41
|
+
statusText = res.statusText;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Fall back to GET if HEAD is not allowed
|
|
45
|
+
const controller2 = new AbortController();
|
|
46
|
+
const timer2 = setTimeout(() => controller2.abort(), TIMEOUT_MS);
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(url, {
|
|
49
|
+
method: "GET",
|
|
50
|
+
redirect: "follow",
|
|
51
|
+
signal: controller2.signal,
|
|
52
|
+
});
|
|
53
|
+
status = res.status;
|
|
54
|
+
statusText = res.statusText;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
status = 0;
|
|
58
|
+
statusText = "timeout or network error";
|
|
59
|
+
}
|
|
60
|
+
clearTimeout(timer2);
|
|
61
|
+
}
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
if (!isSuccessStatus(status)) {
|
|
64
|
+
const severity = status >= 500 ? "critical" : "high";
|
|
65
|
+
let path = url;
|
|
66
|
+
try {
|
|
67
|
+
path = new URL(url).pathname;
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
brokenLinks.push({ url, path, status, statusText, severity });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// skip
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
const summary = brokenLinks.length === 0
|
|
78
|
+
? `All ${uniqueUrls.length} links OK`
|
|
79
|
+
: `${brokenLinks.length} broken link(s) found`;
|
|
80
|
+
return {
|
|
81
|
+
brokenLinks,
|
|
82
|
+
checkedCount: uniqueUrls.length,
|
|
83
|
+
hasBrokenLinks: brokenLinks.length > 0,
|
|
84
|
+
summary,
|
|
85
|
+
};
|
|
86
|
+
}
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export declare const LAXY_API_URL: string;
|
|
2
|
-
export declare function loadToken(): string | null;
|
|
3
|
-
export declare function saveToken(token: string, email: string, expiresInSec: number): void;
|
|
4
|
-
export declare function clearToken(): void;
|
|
5
|
-
export declare function whoami(): void;
|
|
6
|
-
/**
|
|
7
|
-
* Get or create a stable repo_id for the given project directory.
|
|
8
|
-
* Stored in ~/.laxy/repos.json keyed by absolute project path.
|
|
9
|
-
*/
|
|
10
|
-
export declare function getOrCreateRepoId(projectDir: string): string;
|
|
11
|
-
export declare function login(emailArg?: string): Promise<void>;
|
|
1
|
+
export declare const LAXY_API_URL: string;
|
|
2
|
+
export declare function loadToken(): string | null;
|
|
3
|
+
export declare function saveToken(token: string, email: string, expiresInSec: number): void;
|
|
4
|
+
export declare function clearToken(): void;
|
|
5
|
+
export declare function whoami(): void;
|
|
6
|
+
/**
|
|
7
|
+
* Get or create a stable repo_id for the given project directory.
|
|
8
|
+
* Stored in ~/.laxy/repos.json keyed by absolute project path.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getOrCreateRepoId(projectDir: string): string;
|
|
11
|
+
export declare function login(emailArg?: string): Promise<void>;
|