laxy-verify 1.3.0 → 1.3.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.
@@ -0,0 +1,28 @@
1
+ export interface AiFailureContext {
2
+ grade: string;
3
+ blockers: Array<{
4
+ title: string;
5
+ action: string;
6
+ }>;
7
+ lighthouseScores: {
8
+ performance: number;
9
+ accessibility: number;
10
+ seo: number;
11
+ bestPractices: number;
12
+ } | null;
13
+ thresholds: {
14
+ performance: number;
15
+ accessibility: number;
16
+ seo: number;
17
+ bestPractices: number;
18
+ };
19
+ buildErrors: string[];
20
+ e2eFailed: number;
21
+ e2eTotal: number;
22
+ securitySummary?: string;
23
+ }
24
+ export interface AiFailureAnalysis {
25
+ rootCause: string;
26
+ topFixes: string[];
27
+ }
28
+ export declare function requestAiFailureAnalysis(context: AiFailureContext): Promise<AiFailureAnalysis | null>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestAiFailureAnalysis = requestAiFailureAnalysis;
4
+ /**
5
+ * AI failure analysis client (Pro feature).
6
+ *
7
+ * Sends verification failure context to the Laxy API, which returns
8
+ * a root-cause summary and top fixes generated by Claude.
9
+ */
10
+ const auth_js_1 = require("./auth.js");
11
+ async function requestAiFailureAnalysis(context) {
12
+ const token = (0, auth_js_1.loadToken)();
13
+ if (!token)
14
+ return null;
15
+ try {
16
+ const res = await fetch(`${auth_js_1.LAXY_API_URL}/api/v1/analyze-failure`, {
17
+ method: "POST",
18
+ headers: {
19
+ Authorization: `Bearer ${token}`,
20
+ "Content-Type": "application/json",
21
+ },
22
+ body: JSON.stringify(context),
23
+ signal: AbortSignal.timeout(30_000),
24
+ });
25
+ if (!res.ok)
26
+ return null;
27
+ return (await res.json());
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
@@ -1,25 +1,25 @@
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 interface BrokenLinksAuditOptions {
22
- extraRoutes?: string[];
23
- abortSignal?: AbortSignal;
24
- }
25
- export declare function auditBrokenLinks(crawlResult: CrawlResult | undefined, baseUrl: string, options?: BrokenLinksAuditOptions): 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 interface BrokenLinksAuditOptions {
22
+ extraRoutes?: string[];
23
+ abortSignal?: AbortSignal;
24
+ }
25
+ export declare function auditBrokenLinks(crawlResult: CrawlResult | undefined, baseUrl: string, options?: BrokenLinksAuditOptions): Promise<BrokenLinksResult>;
@@ -1,97 +1,97 @@
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, options = {}) {
10
- const allUrls = [];
11
- if (crawlResult) {
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
- }
25
- for (const route of options.extraRoutes ?? []) {
26
- try {
27
- const url = new URL(route, baseUrl).href;
28
- if (!allUrls.includes(url))
29
- allUrls.push(url);
30
- }
31
- catch {
32
- // skip malformed routes
33
- }
34
- }
35
- const uniqueUrls = allUrls;
36
- const brokenLinks = [];
37
- await Promise.all(uniqueUrls.map(async (url) => {
38
- if (options.abortSignal?.aborted)
39
- return;
40
- try {
41
- const controller = new AbortController();
42
- const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
43
- let status = 0;
44
- let statusText = "";
45
- try {
46
- const res = await fetch(url, {
47
- method: "HEAD",
48
- redirect: "follow",
49
- signal: controller.signal,
50
- });
51
- status = res.status;
52
- statusText = res.statusText;
53
- }
54
- catch {
55
- // Fall back to GET if HEAD is not allowed
56
- const controller2 = new AbortController();
57
- const timer2 = setTimeout(() => controller2.abort(), TIMEOUT_MS);
58
- try {
59
- const res = await fetch(url, {
60
- method: "GET",
61
- redirect: "follow",
62
- signal: controller2.signal,
63
- });
64
- status = res.status;
65
- statusText = res.statusText;
66
- }
67
- catch {
68
- status = 0;
69
- statusText = "timeout or network error";
70
- }
71
- clearTimeout(timer2);
72
- }
73
- clearTimeout(timer);
74
- if (!isSuccessStatus(status)) {
75
- const severity = status >= 500 ? "critical" : "high";
76
- let path = url;
77
- try {
78
- path = new URL(url).pathname;
79
- }
80
- catch { }
81
- brokenLinks.push({ url, path, status, statusText, severity });
82
- }
83
- }
84
- catch {
85
- // skip
86
- }
87
- }));
88
- const summary = brokenLinks.length === 0
89
- ? `All ${uniqueUrls.length} links OK`
90
- : `${brokenLinks.length} broken link(s) found`;
91
- return {
92
- brokenLinks,
93
- checkedCount: uniqueUrls.length,
94
- hasBrokenLinks: brokenLinks.length > 0,
95
- summary,
96
- };
97
- }
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, options = {}) {
10
+ const allUrls = [];
11
+ if (crawlResult) {
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
+ }
25
+ for (const route of options.extraRoutes ?? []) {
26
+ try {
27
+ const url = new URL(route, baseUrl).href;
28
+ if (!allUrls.includes(url))
29
+ allUrls.push(url);
30
+ }
31
+ catch {
32
+ // skip malformed routes
33
+ }
34
+ }
35
+ const uniqueUrls = allUrls;
36
+ const brokenLinks = [];
37
+ await Promise.all(uniqueUrls.map(async (url) => {
38
+ if (options.abortSignal?.aborted)
39
+ return;
40
+ try {
41
+ const controller = new AbortController();
42
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
43
+ let status = 0;
44
+ let statusText = "";
45
+ try {
46
+ const res = await fetch(url, {
47
+ method: "HEAD",
48
+ redirect: "follow",
49
+ signal: controller.signal,
50
+ });
51
+ status = res.status;
52
+ statusText = res.statusText;
53
+ }
54
+ catch {
55
+ // Fall back to GET if HEAD is not allowed
56
+ const controller2 = new AbortController();
57
+ const timer2 = setTimeout(() => controller2.abort(), TIMEOUT_MS);
58
+ try {
59
+ const res = await fetch(url, {
60
+ method: "GET",
61
+ redirect: "follow",
62
+ signal: controller2.signal,
63
+ });
64
+ status = res.status;
65
+ statusText = res.statusText;
66
+ }
67
+ catch {
68
+ status = 0;
69
+ statusText = "timeout or network error";
70
+ }
71
+ clearTimeout(timer2);
72
+ }
73
+ clearTimeout(timer);
74
+ if (!isSuccessStatus(status)) {
75
+ const severity = status >= 500 ? "critical" : "high";
76
+ let path = url;
77
+ try {
78
+ path = new URL(url).pathname;
79
+ }
80
+ catch { }
81
+ brokenLinks.push({ url, path, status, statusText, severity });
82
+ }
83
+ }
84
+ catch {
85
+ // skip
86
+ }
87
+ }));
88
+ const summary = brokenLinks.length === 0
89
+ ? `All ${uniqueUrls.length} links OK`
90
+ : `${brokenLinks.length} broken link(s) found`;
91
+ return {
92
+ brokenLinks,
93
+ checkedCount: uniqueUrls.length,
94
+ hasBrokenLinks: brokenLinks.length > 0,
95
+ summary,
96
+ };
97
+ }
package/dist/badge.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare function generateBadge(grade: string): string;
2
- export declare function generateDynamicBadgeMarkdown(repoId: string, apiUrl: string): string;
1
+ export declare function generateBadge(grade: string): string;
2
+ export declare function generateDynamicBadgeMarkdown(repoId: string, apiUrl: string): string;
package/dist/badge.js CHANGED
@@ -1,18 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateBadge = generateBadge;
4
- exports.generateDynamicBadgeMarkdown = generateDynamicBadgeMarkdown;
5
- function generateBadge(grade) {
6
- const gradeLower = grade.toLowerCase();
7
- const colors = {
8
- gold: "yellow",
9
- silver: "brightgreen",
10
- bronze: "blue",
11
- unverified: "lightgrey",
12
- };
13
- const color = colors[gradeLower] ?? "lightgrey";
14
- return `![Laxy Verify: ${grade}](https://img.shields.io/badge/laxy_verify-${gradeLower}-${color})`;
15
- }
16
- function generateDynamicBadgeMarkdown(repoId, apiUrl) {
17
- return `[![Laxy Verify](${apiUrl}/api/badge/${repoId})](${apiUrl})`;
18
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateBadge = generateBadge;
4
+ exports.generateDynamicBadgeMarkdown = generateDynamicBadgeMarkdown;
5
+ function generateBadge(grade) {
6
+ const gradeLower = grade.toLowerCase();
7
+ const colors = {
8
+ gold: "yellow",
9
+ silver: "brightgreen",
10
+ bronze: "blue",
11
+ unverified: "lightgrey",
12
+ };
13
+ const color = colors[gradeLower] ?? "lightgrey";
14
+ return `![Laxy Verify: ${grade}](https://img.shields.io/badge/laxy_verify-${gradeLower}-${color})`;
15
+ }
16
+ function generateDynamicBadgeMarkdown(repoId, apiUrl) {
17
+ return `[![Laxy Verify](${apiUrl}/api/badge/${repoId})](${apiUrl})`;
18
+ }