laxy-verify 1.1.32 → 1.2.0

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.
Files changed (38) hide show
  1. package/README.md +322 -322
  2. package/dist/audit/broken-links.d.ts +21 -21
  3. package/dist/audit/broken-links.js +86 -86
  4. package/dist/auth.d.ts +11 -6
  5. package/dist/auth.js +222 -188
  6. package/dist/cli.js +806 -724
  7. package/dist/comment.d.ts +21 -21
  8. package/dist/comment.js +134 -131
  9. package/dist/crawler.d.ts +36 -35
  10. package/dist/crawler.js +357 -356
  11. package/dist/e2e.d.ts +49 -49
  12. package/dist/e2e.js +565 -539
  13. package/dist/entitlement.d.ts +11 -11
  14. package/dist/entitlement.js +90 -88
  15. package/dist/init.js +87 -87
  16. package/dist/multi-viewport.d.ts +31 -31
  17. package/dist/multi-viewport.js +298 -298
  18. package/dist/playwright-runner.d.ts +16 -16
  19. package/dist/playwright-runner.js +208 -208
  20. package/dist/report-markdown.d.ts +39 -39
  21. package/dist/report-markdown.js +386 -386
  22. package/dist/security-audit.d.ts +9 -9
  23. package/dist/security-audit.js +64 -64
  24. package/dist/serve.d.ts +13 -13
  25. package/dist/serve.js +249 -246
  26. package/dist/trend.d.ts +50 -49
  27. package/dist/trend.js +148 -147
  28. package/dist/verification-core/index.d.ts +3 -3
  29. package/dist/verification-core/index.js +19 -19
  30. package/dist/verification-core/report.d.ts +14 -14
  31. package/dist/verification-core/report.js +409 -404
  32. package/dist/verification-core/tier-policy.d.ts +13 -13
  33. package/dist/verification-core/tier-policy.js +60 -60
  34. package/dist/verification-core/types.d.ts +108 -108
  35. package/dist/verification-core/types.js +2 -2
  36. package/dist/visual-diff.d.ts +26 -26
  37. package/dist/visual-diff.js +178 -178
  38. package/package.json +67 -67
package/dist/comment.d.ts CHANGED
@@ -1,21 +1,21 @@
1
- import type { TrendDelta } from "./trend.js";
2
- interface LaxyResult {
3
- grade: string;
4
- lighthouse: {
5
- performance: number;
6
- accessibility: number;
7
- seo: number;
8
- bestPractices: number;
9
- runs: number;
10
- } | null;
11
- thresholds: {
12
- performance: number;
13
- accessibility: number;
14
- seo: number;
15
- bestPractices: number;
16
- };
17
- exitCode: number;
18
- config_fail_on: string;
19
- }
20
- export declare function postPRComment(result: LaxyResult, trend?: TrendDelta | null): Promise<void>;
21
- export {};
1
+ import type { TrendDelta } from "./trend.js";
2
+ interface LaxyResult {
3
+ grade: string;
4
+ lighthouse: {
5
+ performance: number;
6
+ accessibility: number;
7
+ seo: number;
8
+ bestPractices: number;
9
+ runs: number;
10
+ } | null;
11
+ thresholds: {
12
+ performance: number;
13
+ accessibility: number;
14
+ seo: number;
15
+ bestPractices: number;
16
+ };
17
+ exitCode: number;
18
+ config_fail_on: string;
19
+ }
20
+ export declare function postPRComment(result: LaxyResult, trend?: TrendDelta | null): Promise<void>;
21
+ export {};
package/dist/comment.js CHANGED
@@ -1,131 +1,134 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.postPRComment = postPRComment;
37
- const fs = __importStar(require("node:fs"));
38
- const github_js_1 = require("./github.js");
39
- function renderTrendTable(delta) {
40
- const lines = [
41
- "| Check | This PR | vs Base |",
42
- "|---|---|---|",
43
- ];
44
- const gradeTrendStr = delta.grade.current !== delta.grade.base
45
- ? ` (was ${delta.grade.base})`
46
- : "";
47
- lines.push(`| Grade | **${delta.grade.current}**${gradeTrendStr} | ${delta.grade.base} |`);
48
- function fmtDelta(d) {
49
- if (d === null)
50
- return "—";
51
- if (d > 0)
52
- return `+${d}`;
53
- if (d < 0)
54
- return `${d}`;
55
- return "—";
56
- }
57
- if (delta.performance.current !== null) {
58
- lines.push(`| Performance | ${delta.performance.current} | ${fmtDelta(delta.performance.delta)} |`);
59
- }
60
- if (delta.accessibility.current !== null) {
61
- lines.push(`| Accessibility | ${delta.accessibility.current} | ${fmtDelta(delta.accessibility.delta)} |`);
62
- }
63
- if (delta.seo.current !== null) {
64
- lines.push(`| SEO | ${delta.seo.current} | ${fmtDelta(delta.seo.delta)} |`);
65
- }
66
- if (delta.bestPractices.current !== null) {
67
- lines.push(`| Best Practices | ${delta.bestPractices.current} | ${fmtDelta(delta.bestPractices.delta)} |`);
68
- }
69
- if (delta.e2e.current !== null) {
70
- lines.push(`| E2E | ${delta.e2e.current} | ${delta.e2e.base ?? "—"} (base) |`);
71
- }
72
- return `${lines.join("\n")}\n`;
73
- }
74
- async function postPRComment(result, trend) {
75
- const ctx = (0, github_js_1.getGitHubContext)();
76
- if (!ctx || ctx.eventName !== "pull_request")
77
- return;
78
- let prNumber = 0;
79
- if (ctx.eventPath && fs.existsSync(ctx.eventPath)) {
80
- const event = JSON.parse(fs.readFileSync(ctx.eventPath, "utf-8"));
81
- prNumber = event.pull_request?.number ?? 0;
82
- }
83
- if (!prNumber)
84
- return;
85
- const grade = result.grade ?? "Unverified";
86
- const lh = result.lighthouse;
87
- const t = result.thresholds;
88
- let lhTable = "";
89
- if (lh) {
90
- lhTable = `| Performance | Accessibility | SEO | Best Practices |\n|---|---|---|---|\n| ${lh.performance} / ${t.performance} | ${lh.accessibility} / ${t.accessibility} | ${lh.seo} / ${t.seo} | ${lh.bestPractices} / ${t.bestPractices} |\n\n`;
91
- }
92
- const trendTable = trend ? `${renderTrendTable(trend)}\n` : "";
93
- const passed = result.exitCode === 0;
94
- const statusLabel = passed ? "[PASS]" : "[HOLD]";
95
- const headline = passed ? "No deployment blockers found" : "Deployment blockers found";
96
- const summary = passed
97
- ? `This PR passed the current verification gate. Grade summary: **${grade}**.`
98
- : grade === "Unverified"
99
- ? "The production build failed or verification could not complete, so this PR should be held."
100
- : `This PR did not clear the current verification gate. Grade summary: **${grade}**.`;
101
- const body = `## ${statusLabel} Laxy Verify: ${headline}
102
-
103
- ${summary}
104
-
105
- ${trendTable}${lhTable}**Fail-on threshold**: ${result.config_fail_on ?? "bronze"}
106
-
107
- Grade remains available for automation, but this check should be read first as a merge and release blocker gate.
108
-
109
- ---
110
- [Open laxy-verify docs](https://github.com/SUNgm24/Laxy/tree/main/laxy-verify)`;
111
- const [owner, repo] = ctx.repository.split("/");
112
- const url = `https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`;
113
- try {
114
- const res = await fetch(url, {
115
- method: "POST",
116
- headers: {
117
- Authorization: `Bearer ${ctx.token}`,
118
- Accept: "application/vnd.github.v3+json",
119
- "Content-Type": "application/json",
120
- },
121
- body: JSON.stringify({ body }),
122
- });
123
- if (!res.ok) {
124
- console.warn(`GitHub PR comment API returned ${res.status}; skipping comment.`);
125
- return;
126
- }
127
- }
128
- catch (err) {
129
- console.warn(`GitHub PR comment request failed: ${err instanceof Error ? err.message : String(err)}`);
130
- }
131
- }
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.postPRComment = postPRComment;
37
+ const fs = __importStar(require("node:fs"));
38
+ const github_js_1 = require("./github.js");
39
+ const trend_js_1 = require("./trend.js");
40
+ function renderTrendTable(delta) {
41
+ const lines = [
42
+ "| Check | This PR | vs Base |",
43
+ "|---|---|---|",
44
+ ];
45
+ const gradeUp = (0, trend_js_1.gradeIndex)(delta.grade.current) > (0, trend_js_1.gradeIndex)(delta.grade.base);
46
+ const gradeDown = (0, trend_js_1.gradeIndex)(delta.grade.current) < (0, trend_js_1.gradeIndex)(delta.grade.base);
47
+ const gradeTrendStr = gradeUp ? ` ↑ (was ${delta.grade.base})` :
48
+ gradeDown ? ` ↓ (was ${delta.grade.base})` :
49
+ "";
50
+ lines.push(`| Grade | **${delta.grade.current}**${gradeTrendStr} | ${delta.grade.base} |`);
51
+ function fmtDelta(d) {
52
+ if (d === null)
53
+ return "—";
54
+ if (d > 0)
55
+ return `+${d}`;
56
+ if (d < 0)
57
+ return `${d}`;
58
+ return "—";
59
+ }
60
+ if (delta.performance.current !== null) {
61
+ lines.push(`| Performance | ${delta.performance.current} | ${fmtDelta(delta.performance.delta)} |`);
62
+ }
63
+ if (delta.accessibility.current !== null) {
64
+ lines.push(`| Accessibility | ${delta.accessibility.current} | ${fmtDelta(delta.accessibility.delta)} |`);
65
+ }
66
+ if (delta.seo.current !== null) {
67
+ lines.push(`| SEO | ${delta.seo.current} | ${fmtDelta(delta.seo.delta)} |`);
68
+ }
69
+ if (delta.bestPractices.current !== null) {
70
+ lines.push(`| Best Practices | ${delta.bestPractices.current} | ${fmtDelta(delta.bestPractices.delta)} |`);
71
+ }
72
+ if (delta.e2e.current !== null) {
73
+ lines.push(`| E2E | ${delta.e2e.current} | ${delta.e2e.base ?? "—"} (base) |`);
74
+ }
75
+ return `${lines.join("\n")}\n`;
76
+ }
77
+ async function postPRComment(result, trend) {
78
+ const ctx = (0, github_js_1.getGitHubContext)();
79
+ if (!ctx || ctx.eventName !== "pull_request")
80
+ return;
81
+ let prNumber = 0;
82
+ if (ctx.eventPath && fs.existsSync(ctx.eventPath)) {
83
+ const event = JSON.parse(fs.readFileSync(ctx.eventPath, "utf-8"));
84
+ prNumber = event.pull_request?.number ?? 0;
85
+ }
86
+ if (!prNumber)
87
+ return;
88
+ const grade = result.grade ?? "Unverified";
89
+ const lh = result.lighthouse;
90
+ const t = result.thresholds;
91
+ let lhTable = "";
92
+ if (lh) {
93
+ lhTable = `| Performance | Accessibility | SEO | Best Practices |\n|---|---|---|---|\n| ${lh.performance} / ${t.performance} | ${lh.accessibility} / ${t.accessibility} | ${lh.seo} / ${t.seo} | ${lh.bestPractices} / ${t.bestPractices} |\n\n`;
94
+ }
95
+ const trendTable = trend ? `${renderTrendTable(trend)}\n` : "";
96
+ const passed = result.exitCode === 0;
97
+ const statusLabel = passed ? "[PASS]" : "[HOLD]";
98
+ const headline = passed ? "No deployment blockers found" : "Deployment blockers found";
99
+ const summary = passed
100
+ ? `This PR passed the current verification gate. Grade summary: **${grade}**.`
101
+ : grade === "Unverified"
102
+ ? "The production build failed or verification could not complete, so this PR should be held."
103
+ : `This PR did not clear the current verification gate. Grade summary: **${grade}**.`;
104
+ const body = `## ${statusLabel} Laxy Verify: ${headline}
105
+
106
+ ${summary}
107
+
108
+ ${trendTable}${lhTable}**Fail-on threshold**: ${result.config_fail_on ?? "bronze"}
109
+
110
+ Grade remains available for automation, but this check should be read first as a merge and release blocker gate.
111
+
112
+ ---
113
+ [Open laxy-verify docs](https://github.com/SUNgm24/Laxy/tree/main/laxy-verify)`;
114
+ const [owner, repo] = ctx.repository.split("/");
115
+ const url = `https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`;
116
+ try {
117
+ const res = await fetch(url, {
118
+ method: "POST",
119
+ headers: {
120
+ Authorization: `Bearer ${ctx.token}`,
121
+ Accept: "application/vnd.github.v3+json",
122
+ "Content-Type": "application/json",
123
+ },
124
+ body: JSON.stringify({ body }),
125
+ });
126
+ if (!res.ok) {
127
+ console.warn(`GitHub PR comment API returned ${res.status}; skipping comment.`);
128
+ return;
129
+ }
130
+ }
131
+ catch (err) {
132
+ console.warn(`GitHub PR comment request failed: ${err instanceof Error ? err.message : String(err)}`);
133
+ }
134
+ }
package/dist/crawler.d.ts CHANGED
@@ -1,35 +1,36 @@
1
- import type { E2EScenario } from "./e2e.js";
2
- import type { VerificationTier } from "./verification-core/types.js";
3
- export interface CrawlPage {
4
- url: string;
5
- path: string;
6
- title: string;
7
- forms: CrawlForm[];
8
- buttons: string[];
9
- internalLinks: string[];
10
- hasConsoleErrors: boolean;
11
- }
12
- export interface CrawlForm {
13
- selector: string;
14
- inputs: {
15
- selector: string;
16
- type: string;
17
- placeholder?: string;
18
- }[];
19
- submitSelector?: string;
20
- }
21
- export interface CrawlResult {
22
- pages: CrawlPage[];
23
- totalLinks: number;
24
- crawledCount: number;
25
- }
26
- export interface CrawlOptions {
27
- maxDepth?: number;
28
- maxPages?: number;
29
- timeout?: number;
30
- }
31
- export declare function crawlApp(baseUrl: string, options?: CrawlOptions): Promise<CrawlResult>;
32
- /**
33
- * Generate E2E scenarios from crawl results.
34
- */
35
- export declare function buildScenariosFromCrawl(crawlResult: CrawlResult, tier: VerificationTier): E2EScenario[];
1
+ import type { E2EScenario } from "./e2e.js";
2
+ import type { VerificationTier } from "./verification-core/types.js";
3
+ export interface CrawlPage {
4
+ url: string;
5
+ path: string;
6
+ title: string;
7
+ forms: CrawlForm[];
8
+ buttons: string[];
9
+ internalLinks: string[];
10
+ hasConsoleErrors: boolean;
11
+ consoleErrors: string[];
12
+ }
13
+ export interface CrawlForm {
14
+ selector: string;
15
+ inputs: {
16
+ selector: string;
17
+ type: string;
18
+ placeholder?: string;
19
+ }[];
20
+ submitSelector?: string;
21
+ }
22
+ export interface CrawlResult {
23
+ pages: CrawlPage[];
24
+ totalLinks: number;
25
+ crawledCount: number;
26
+ }
27
+ export interface CrawlOptions {
28
+ maxDepth?: number;
29
+ maxPages?: number;
30
+ timeout?: number;
31
+ }
32
+ export declare function crawlApp(baseUrl: string, options?: CrawlOptions): Promise<CrawlResult>;
33
+ /**
34
+ * Generate E2E scenarios from crawl results.
35
+ */
36
+ export declare function buildScenariosFromCrawl(crawlResult: CrawlResult, tier: VerificationTier): E2EScenario[];