laxy-verify 1.2.2 → 1.2.3
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/README.md +181 -47
- package/dist/a11y-deep.d.ts +20 -0
- package/dist/a11y-deep.js +161 -0
- package/dist/ai-analysis.d.ts +28 -0
- package/dist/ai-analysis.js +32 -0
- package/dist/audit/broken-links.d.ts +5 -1
- package/dist/audit/broken-links.js +23 -12
- package/dist/bundle-size.d.ts +14 -0
- package/dist/bundle-size.js +209 -0
- package/dist/cli.js +391 -13
- package/dist/compare-env.d.ts +23 -0
- package/dist/compare-env.js +55 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +106 -1
- package/dist/entitlement.d.ts +2 -0
- package/dist/entitlement.js +5 -1
- package/dist/init-analysis.d.ts +6 -0
- package/dist/init-analysis.js +302 -0
- package/dist/init.js +66 -0
- package/dist/lighthouse.d.ts +31 -1
- package/dist/lighthouse.js +76 -3
- package/dist/outdated-check.d.ts +17 -0
- package/dist/outdated-check.js +123 -0
- package/dist/report-markdown.d.ts +14 -0
- package/dist/report-markdown.js +21 -0
- package/dist/route-discovery.d.ts +7 -0
- package/dist/route-discovery.js +108 -0
- package/dist/secret-scan.d.ts +15 -0
- package/dist/secret-scan.js +218 -0
- package/dist/security-audit.d.ts +9 -1
- package/dist/security-audit.js +87 -24
- package/dist/seo-deep.d.ts +24 -0
- package/dist/seo-deep.js +147 -0
- package/dist/typecheck.d.ts +8 -0
- package/dist/typecheck.js +99 -0
- package/dist/verification-core/report.js +117 -0
- package/dist/verification-core/types.d.ts +58 -2
- package/dist/visual-diff.d.ts +8 -1
- package/dist/visual-diff.js +53 -8
- package/dist/vitals-budget.d.ts +23 -0
- package/dist/vitals-budget.js +168 -0
- package/package.json +1 -1
|
@@ -0,0 +1,209 @@
|
|
|
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.runBundleSize = runBundleSize;
|
|
37
|
+
/**
|
|
38
|
+
* Bundle size analysis.
|
|
39
|
+
*
|
|
40
|
+
* Parses Next.js and Vite build output to report first-load JS and
|
|
41
|
+
* largest chunk sizes. Advisory-only — does not block deployment.
|
|
42
|
+
*/
|
|
43
|
+
const fs = __importStar(require("node:fs"));
|
|
44
|
+
const path = __importStar(require("node:path"));
|
|
45
|
+
const DEFAULT_FIRST_LOAD_THRESHOLD_KB = 200;
|
|
46
|
+
const DEFAULT_LARGEST_CHUNK_THRESHOLD_KB = 300;
|
|
47
|
+
function parseNextBuildOutput(projectDir) {
|
|
48
|
+
// Next.js stores build output in .next/build-manifest.json and .next/routes-manifest.json
|
|
49
|
+
// The most reliable source is .next/build-manifest.json for pages and their chunks
|
|
50
|
+
const buildManifestPath = path.join(projectDir, ".next", "build-manifest.json");
|
|
51
|
+
if (!fs.existsSync(buildManifestPath))
|
|
52
|
+
return null;
|
|
53
|
+
try {
|
|
54
|
+
const manifest = JSON.parse(fs.readFileSync(buildManifestPath, "utf-8"));
|
|
55
|
+
// Collect all chunk files referenced in the manifest
|
|
56
|
+
const allChunks = new Set();
|
|
57
|
+
const pages = manifest.pages ?? {};
|
|
58
|
+
for (const pageChunks of Object.values(pages)) {
|
|
59
|
+
if (Array.isArray(pageChunks)) {
|
|
60
|
+
for (const chunk of pageChunks) {
|
|
61
|
+
allChunks.add(chunk);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Measure chunk sizes from .next/static
|
|
66
|
+
const chunks = [];
|
|
67
|
+
for (const chunkPath of allChunks) {
|
|
68
|
+
const fullPath = path.join(projectDir, ".next", chunkPath);
|
|
69
|
+
if (!fs.existsSync(fullPath))
|
|
70
|
+
continue;
|
|
71
|
+
try {
|
|
72
|
+
const stat = fs.statSync(fullPath);
|
|
73
|
+
const name = path.basename(chunkPath);
|
|
74
|
+
chunks.push({ name, sizeKb: Math.round(stat.size / 1024) });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// skip unreadable files
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (chunks.length === 0)
|
|
81
|
+
return null;
|
|
82
|
+
// Sort by size descending
|
|
83
|
+
chunks.sort((a, b) => b.sizeKb - a.sizeKb);
|
|
84
|
+
const largest = chunks[0];
|
|
85
|
+
const totalAssetsKb = chunks.reduce((sum, c) => sum + c.sizeKb, 0);
|
|
86
|
+
// First-load JS: sum of all chunks for the "/" page (usually _app + _buildManifest + page chunk)
|
|
87
|
+
const homeChunks = pages["/"] ?? pages["/index"] ?? [];
|
|
88
|
+
const sharedChunks = pages["/_app"] ?? [];
|
|
89
|
+
const firstLoadFiles = [...homeChunks, ...sharedChunks];
|
|
90
|
+
let firstLoadJsKb = 0;
|
|
91
|
+
for (const chunkPath of firstLoadFiles) {
|
|
92
|
+
const fullPath = path.join(projectDir, ".next", chunkPath);
|
|
93
|
+
try {
|
|
94
|
+
if (fs.existsSync(fullPath)) {
|
|
95
|
+
firstLoadJsKb += Math.round(fs.statSync(fullPath).size / 1024);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// skip
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const advisory = buildAdvisory(firstLoadJsKb, largest.sizeKb, largest.name);
|
|
103
|
+
return {
|
|
104
|
+
framework: "next",
|
|
105
|
+
firstLoadJsKb: firstLoadJsKb || null,
|
|
106
|
+
largestChunkKb: largest.sizeKb,
|
|
107
|
+
largestChunkName: largest.name,
|
|
108
|
+
totalAssetsKb,
|
|
109
|
+
advisory,
|
|
110
|
+
chunks: chunks.slice(0, 10),
|
|
111
|
+
skipped: false,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function parseViteBuildOutput(projectDir) {
|
|
119
|
+
// Vite outputs to dist/ by default, manifest in .vite/manifest.json or dist/.vite/manifest.json
|
|
120
|
+
const distDir = path.join(projectDir, "dist");
|
|
121
|
+
if (!fs.existsSync(distDir))
|
|
122
|
+
return null;
|
|
123
|
+
const chunks = [];
|
|
124
|
+
function walkDist(dir) {
|
|
125
|
+
let entries;
|
|
126
|
+
try {
|
|
127
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
for (const entry of entries) {
|
|
133
|
+
const fullPath = path.join(dir, entry.name);
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
walkDist(fullPath);
|
|
136
|
+
}
|
|
137
|
+
else if (entry.isFile() && /\.(js|mjs|css)$/.test(entry.name)) {
|
|
138
|
+
try {
|
|
139
|
+
const stat = fs.statSync(fullPath);
|
|
140
|
+
const relativePath = path.relative(distDir, fullPath).replace(/\\/g, "/");
|
|
141
|
+
chunks.push({ name: relativePath, sizeKb: Math.round(stat.size / 1024) });
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// skip
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
walkDist(distDir);
|
|
150
|
+
if (chunks.length === 0)
|
|
151
|
+
return null;
|
|
152
|
+
chunks.sort((a, b) => b.sizeKb - a.sizeKb);
|
|
153
|
+
const largest = chunks[0];
|
|
154
|
+
const totalAssetsKb = chunks.reduce((sum, c) => sum + c.sizeKb, 0);
|
|
155
|
+
// First-load: index.html + referenced JS
|
|
156
|
+
const indexJsChunks = chunks.filter((c) => c.name.startsWith("assets/") && c.name.includes("index"));
|
|
157
|
+
const firstLoadJsKb = indexJsChunks.length > 0
|
|
158
|
+
? indexJsChunks.reduce((sum, c) => sum + c.sizeKb, 0)
|
|
159
|
+
: null;
|
|
160
|
+
const advisory = buildAdvisory(firstLoadJsKb, largest.sizeKb, largest.name);
|
|
161
|
+
return {
|
|
162
|
+
framework: "vite",
|
|
163
|
+
firstLoadJsKb,
|
|
164
|
+
largestChunkKb: largest.sizeKb,
|
|
165
|
+
largestChunkName: largest.name,
|
|
166
|
+
totalAssetsKb,
|
|
167
|
+
advisory,
|
|
168
|
+
chunks: chunks.slice(0, 10),
|
|
169
|
+
skipped: false,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function buildAdvisory(firstLoadKb, largestKb, largestName) {
|
|
173
|
+
const parts = [];
|
|
174
|
+
if (firstLoadKb !== null && firstLoadKb > DEFAULT_FIRST_LOAD_THRESHOLD_KB) {
|
|
175
|
+
parts.push(`first-load JS ${firstLoadKb}KB exceeds ${DEFAULT_FIRST_LOAD_THRESHOLD_KB}KB advisory threshold`);
|
|
176
|
+
}
|
|
177
|
+
if (largestKb > DEFAULT_LARGEST_CHUNK_THRESHOLD_KB) {
|
|
178
|
+
parts.push(`largest chunk ${largestName} is ${largestKb}KB (>${DEFAULT_LARGEST_CHUNK_THRESHOLD_KB}KB advisory)`);
|
|
179
|
+
}
|
|
180
|
+
if (parts.length === 0) {
|
|
181
|
+
const firstLoadNote = firstLoadKb !== null ? `first-load ${firstLoadKb}KB, ` : "";
|
|
182
|
+
return `${firstLoadNote}largest chunk ${largestName} ${largestKb}KB — within advisory thresholds`;
|
|
183
|
+
}
|
|
184
|
+
return parts.join("; ");
|
|
185
|
+
}
|
|
186
|
+
async function runBundleSize(projectDir) {
|
|
187
|
+
console.log(" Running bundle size analysis...");
|
|
188
|
+
const nextResult = parseNextBuildOutput(projectDir);
|
|
189
|
+
if (nextResult) {
|
|
190
|
+
console.log(` Bundle (Next.js): ${nextResult.advisory}`);
|
|
191
|
+
return nextResult;
|
|
192
|
+
}
|
|
193
|
+
const viteResult = parseViteBuildOutput(projectDir);
|
|
194
|
+
if (viteResult) {
|
|
195
|
+
console.log(` Bundle (Vite): ${viteResult.advisory}`);
|
|
196
|
+
return viteResult;
|
|
197
|
+
}
|
|
198
|
+
console.log(" Bundle size: skipped (no .next or dist directory found)");
|
|
199
|
+
return {
|
|
200
|
+
framework: "unknown",
|
|
201
|
+
firstLoadJsKb: null,
|
|
202
|
+
largestChunkKb: null,
|
|
203
|
+
largestChunkName: null,
|
|
204
|
+
totalAssetsKb: null,
|
|
205
|
+
advisory: "No build output found for bundle analysis",
|
|
206
|
+
chunks: [],
|
|
207
|
+
skipped: true,
|
|
208
|
+
};
|
|
209
|
+
}
|