audit0 0.1.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 (42) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.js +264 -0
  3. package/dist/config/defaults.d.ts +2 -0
  4. package/dist/config/defaults.js +2 -0
  5. package/dist/config/define.d.ts +2 -0
  6. package/dist/config/define.js +112 -0
  7. package/dist/config/errors.d.ts +6 -0
  8. package/dist/config/errors.js +10 -0
  9. package/dist/config/marker.d.ts +3 -0
  10. package/dist/config/marker.js +27 -0
  11. package/dist/config/schema.d.ts +3 -0
  12. package/dist/config/schema.js +66 -0
  13. package/dist/config/types.d.ts +107 -0
  14. package/dist/config/types.js +1 -0
  15. package/dist/engine/artifacts.d.mts +11 -0
  16. package/dist/engine/artifacts.mjs +92 -0
  17. package/dist/engine/audit-archive.d.mts +7 -0
  18. package/dist/engine/audit-archive.mjs +183 -0
  19. package/dist/engine/findings.d.mts +59 -0
  20. package/dist/engine/findings.mjs +111 -0
  21. package/dist/engine/inspect.d.mts +36 -0
  22. package/dist/engine/inspect.mjs +239 -0
  23. package/dist/engine/navigation-requests.d.mts +50 -0
  24. package/dist/engine/navigation-requests.mjs +272 -0
  25. package/dist/engine/navigation.d.mts +91 -0
  26. package/dist/engine/navigation.mjs +427 -0
  27. package/dist/engine/page-diagnostics.d.mts +18 -0
  28. package/dist/engine/page-diagnostics.mjs +997 -0
  29. package/dist/engine/report.d.mts +1 -0
  30. package/dist/engine/report.mjs +577 -0
  31. package/dist/engine/settings.d.mts +11 -0
  32. package/dist/engine/settings.mjs +8 -0
  33. package/dist/findings.d.ts +1 -0
  34. package/dist/findings.js +1 -0
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.js +5 -0
  37. package/dist/infra.d.ts +2 -0
  38. package/dist/infra.js +2 -0
  39. package/dist/run.d.ts +30 -0
  40. package/dist/run.js +319 -0
  41. package/package.json +66 -0
  42. package/schema/audit-v1.schema.json +82 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function cli(argv: string[]): Promise<void>;
3
+ export declare function main(): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
3
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
4
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
5
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
6
+ });
7
+ }
8
+ return path;
9
+ };
10
+ import { realpathSync } from "node:fs";
11
+ import { access, readFile, writeFile } from "node:fs/promises";
12
+ import { dirname, resolve } from "node:path";
13
+ import { fileURLToPath, pathToFileURL } from "node:url";
14
+ import { AuditConfigError } from "./config/errors.js";
15
+ import { buildArtifactManifest } from "./engine/artifacts.mjs";
16
+ import { validateAuditDocument, readAuditBundle, writeAuditArchive, } from "./engine/audit-archive.mjs";
17
+ import { writeReport } from "./engine/report.mjs";
18
+ const CONFIG_CANDIDATES = ["audit.config.ts", "audit.config.mjs", "audit.config.js"];
19
+ const USAGE = `Usage: audit0 <command> [options]
20
+
21
+ Commands:
22
+ run [options] Run the configured pages and journeys
23
+ --repeats <n> Repetitions per case (1-20)
24
+ --only <id> Restrict to a page or journey id (repeatable)
25
+ --pages-only Skip journeys
26
+ --navigation-only Skip pages
27
+ --headed Run a headed browser
28
+ --output <dir> Artifact directory (default: artifacts)
29
+ --config <path> Config file (default: audit.config.ts|mjs|js)
30
+ inspect <path|url> [options] Capture a page's links, headings, markers and HTML
31
+ --click <href> Hover and click the visible link with this exact href
32
+ --selector <css> Count matches and audit-visible matches (repeatable)
33
+ --origin <url> Origin for relative paths (default: AUDIT_ORIGIN or config)
34
+ --output <dir> Evidence directory (default: artifacts/inspect)
35
+ --config <path> Config whose page markers are evaluated (optional)
36
+ --headed Run a headed browser
37
+ report <audit.json> Render report.html beside the audit
38
+ archive [run|audit.json] [out] Write audit.zip
39
+ archive verify <audit.zip> Verify a bundle
40
+ assets [run|audit.json] Rebuild the asset manifest
41
+ validate <audit.json> Validate an audit document
42
+ `;
43
+ function write(chunk) {
44
+ process.stdout.write(chunk);
45
+ }
46
+ function writeError(chunk) {
47
+ process.stderr.write(chunk);
48
+ }
49
+ async function exists(path) {
50
+ try {
51
+ await access(path);
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ async function findDefaultConfig() {
59
+ for (const candidate of CONFIG_CANDIDATES) {
60
+ const path = resolve(candidate);
61
+ if (await exists(path))
62
+ return path;
63
+ }
64
+ return null;
65
+ }
66
+ async function findConfig(explicit) {
67
+ if (explicit)
68
+ return resolve(explicit);
69
+ const found = await findDefaultConfig();
70
+ if (found)
71
+ return found;
72
+ throw new AuditConfigError("invalid-config", "", `no config found; looked for ${CONFIG_CANDIDATES.join(", ")}`);
73
+ }
74
+ async function loadConfig(explicit) {
75
+ const file = await findConfig(explicit);
76
+ const module = await import(__rewriteRelativeImportExtension(pathToFileURL(file).href));
77
+ if (module.default)
78
+ return module.default;
79
+ throw new AuditConfigError("invalid-config", "", `config ${file} must default-export defineAudit(...)`);
80
+ }
81
+ function parseRunOptions(args) {
82
+ const options = { only: [] };
83
+ let configPath;
84
+ for (let index = 0; index < args.length; index++) {
85
+ const arg = args[index];
86
+ if (arg === "--repeats")
87
+ options.repeats = Number(args[++index]);
88
+ else if (arg === "--only")
89
+ options.only?.push(args[++index] ?? "");
90
+ else if (arg === "--pages-only")
91
+ options.pagesOnly = true;
92
+ else if (arg === "--navigation-only")
93
+ options.navigationOnly = true;
94
+ else if (arg === "--headed")
95
+ options.headed = true;
96
+ else if (arg === "--output")
97
+ options.outputDirectory = args[++index];
98
+ else if (arg === "--config")
99
+ configPath = args[++index];
100
+ else
101
+ throw new AuditConfigError("invalid-config", "", `unknown option "${arg}"`);
102
+ }
103
+ return { options, configPath };
104
+ }
105
+ function parseInspectArgs(args) {
106
+ const parsed = { selectors: [], headed: false };
107
+ for (let index = 0; index < args.length; index++) {
108
+ const arg = args[index];
109
+ if (arg === "--click")
110
+ parsed.click = args[++index];
111
+ else if (arg === "--selector")
112
+ parsed.selectors.push(args[++index] ?? "");
113
+ else if (arg === "--origin")
114
+ parsed.origin = args[++index];
115
+ else if (arg === "--output")
116
+ parsed.outputDirectory = args[++index];
117
+ else if (arg === "--config")
118
+ parsed.configPath = args[++index];
119
+ else if (arg === "--headed")
120
+ parsed.headed = true;
121
+ else if (arg.startsWith("--") || parsed.target !== undefined)
122
+ throw new AuditConfigError("invalid-config", "", `unknown inspect argument "${arg}"`);
123
+ else
124
+ parsed.target = arg;
125
+ }
126
+ return parsed;
127
+ }
128
+ async function commandInspect(args) {
129
+ const parsed = parseInspectArgs(args);
130
+ if (!parsed.target) {
131
+ throw new AuditConfigError("invalid-config", "", "Usage: audit0 inspect <path|url> [--click <href>] [--selector <css>]");
132
+ }
133
+ const configPath = parsed.configPath ? resolve(parsed.configPath) : await findDefaultConfig();
134
+ const config = configPath ? await loadConfig(configPath) : null;
135
+ const { formatInspectCapture, inspectUrl, resolveInspectUrl } = await import("./engine/inspect.mjs");
136
+ const { directory } = await inspectUrl({
137
+ url: resolveInspectUrl(parsed.target, parsed.origin ?? process.env.AUDIT_ORIGIN ?? config?.origin),
138
+ click: parsed.click ?? null,
139
+ selectors: parsed.selectors,
140
+ pages: config?.pages ?? [],
141
+ settings: config?.settings,
142
+ outputDirectory: parsed.outputDirectory,
143
+ headed: parsed.headed,
144
+ onCapture: (capture) => write(formatInspectCapture(capture)),
145
+ });
146
+ write(`Evidence: ${directory}\n`);
147
+ }
148
+ async function resolveAuditPath(supplied) {
149
+ if (supplied) {
150
+ const resolved = resolve(supplied);
151
+ return resolved.endsWith(".json") ? resolved : resolve(resolved, "audit.json");
152
+ }
153
+ const latest = JSON.parse(await readFile(resolve("artifacts/latest.json"), "utf8"));
154
+ return resolve(latest.directory, "audit.json");
155
+ }
156
+ async function commandRun(args) {
157
+ const { options, configPath } = parseRunOptions(args);
158
+ const config = await loadConfig(configPath);
159
+ const { runAudit } = await import("./run.js");
160
+ await runAudit(config, options);
161
+ }
162
+ async function commandReport(args) {
163
+ const auditArg = args[0] ?? "";
164
+ if (args.length !== 1 || auditArg === "--help" || auditArg === "-h") {
165
+ writeError("Usage: audit0 report <path/to/audit.json>\n");
166
+ process.exitCode = args.length === 1 && (auditArg === "--help" || auditArg === "-h") ? 0 : 1;
167
+ return;
168
+ }
169
+ try {
170
+ const auditPath = resolve(auditArg);
171
+ const audit = JSON.parse(await readFile(auditPath, "utf8"));
172
+ const reportPath = await writeReport(audit, dirname(auditPath));
173
+ write(`${reportPath}\n`);
174
+ }
175
+ catch (error) {
176
+ writeError(`Could not generate report: ${error.message}\n`);
177
+ process.exitCode = 1;
178
+ }
179
+ }
180
+ async function commandArchive(args) {
181
+ if (args[0] === "--verify" || args[0] === "verify") {
182
+ const archiveArg = args[1];
183
+ if (!archiveArg) {
184
+ throw new AuditConfigError("invalid-config", "", "Usage: audit0 archive verify <audit.zip>");
185
+ }
186
+ const archivePath = resolve(archiveArg);
187
+ await readAuditBundle(archivePath);
188
+ write(`Verified ${archivePath}\n`);
189
+ return;
190
+ }
191
+ const auditPath = await resolveAuditPath(args[0]);
192
+ const outputPath = args[1] ? resolve(args[1]) : resolve(dirname(auditPath), "audit.zip");
193
+ write(`${await writeAuditArchive(auditPath, outputPath)}\n`);
194
+ }
195
+ async function commandAssets(args) {
196
+ const auditPath = await resolveAuditPath(args[0]);
197
+ const audit = JSON.parse(await readFile(auditPath, "utf8"));
198
+ audit.assets = await buildArtifactManifest(dirname(auditPath), audit);
199
+ await writeFile(auditPath, JSON.stringify(audit, null, 2));
200
+ write(`Manifested ${audit.assets.files.length} images in ${auditPath}\n`);
201
+ if (audit.assets.missing.length)
202
+ process.exitCode = 1;
203
+ }
204
+ async function commandValidate(args) {
205
+ if (!args[0])
206
+ throw new AuditConfigError("invalid-config", "", "Usage: audit0 validate <audit.json>");
207
+ const auditPath = resolve(args[0]);
208
+ const audit = JSON.parse(await readFile(auditPath, "utf8"));
209
+ await validateAuditDocument(audit);
210
+ write(`Valid ${auditPath}\n`);
211
+ }
212
+ export async function cli(argv) {
213
+ const [command, ...args] = argv;
214
+ if (!command || command === "--help" || command === "-h") {
215
+ write(USAGE);
216
+ return;
217
+ }
218
+ switch (command) {
219
+ case "run":
220
+ await commandRun(args);
221
+ return;
222
+ case "inspect":
223
+ await commandInspect(args);
224
+ return;
225
+ case "report":
226
+ await commandReport(args);
227
+ return;
228
+ case "archive":
229
+ await commandArchive(args);
230
+ return;
231
+ case "assets":
232
+ await commandAssets(args);
233
+ return;
234
+ case "validate":
235
+ await commandValidate(args);
236
+ return;
237
+ default:
238
+ writeError(USAGE);
239
+ process.exitCode = 1;
240
+ }
241
+ }
242
+ export async function main() {
243
+ try {
244
+ await cli(process.argv.slice(2).filter((argument) => argument !== "--"));
245
+ }
246
+ catch (error) {
247
+ writeError(`${error.message}\n`);
248
+ process.exitCode = 1;
249
+ }
250
+ }
251
+ function isDirectInvocation() {
252
+ const invoked = process.argv[1];
253
+ if (!invoked)
254
+ return false;
255
+ try {
256
+ return realpathSync(invoked) === fileURLToPath(import.meta.url);
257
+ }
258
+ catch {
259
+ return false;
260
+ }
261
+ }
262
+ if (isDirectInvocation()) {
263
+ await main();
264
+ }
@@ -0,0 +1,2 @@
1
+ import type { AuditSettings } from "./types.ts";
2
+ export declare const defaultSettings: AuditSettings;
@@ -0,0 +1,2 @@
1
+ import { defaultSettings as engineDefaultSettings } from "../engine/settings.mjs";
2
+ export const defaultSettings = engineDefaultSettings;
@@ -0,0 +1,2 @@
1
+ import type { AuditConfig, AuditConfigInput } from "./types.ts";
2
+ export declare function defineAudit(input: AuditConfigInput): AuditConfig;
@@ -0,0 +1,112 @@
1
+ import { defaultSettings } from "./defaults.js";
2
+ import { AuditConfigError } from "./errors.js";
3
+ import { normalizeMarker } from "./marker.js";
4
+ import { auditConfigInputSchema } from "./schema.js";
5
+ function deepFreeze(value) {
6
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
7
+ Object.freeze(value);
8
+ for (const key of Object.keys(value)) {
9
+ deepFreeze(value[key]);
10
+ }
11
+ }
12
+ return value;
13
+ }
14
+ function assertUniqueIds(items, path) {
15
+ const seen = new Set();
16
+ for (const [index, item] of items.entries()) {
17
+ if (seen.has(item.id)) {
18
+ throw new AuditConfigError("duplicate-id", `${path}[${index}].id`, `duplicate id "${item.id}"`);
19
+ }
20
+ seen.add(item.id);
21
+ }
22
+ }
23
+ function assertMarkerNames(page, path) {
24
+ const known = new Set(Object.keys(page.markers));
25
+ const groups = [
26
+ ["shell", page.shell ?? []],
27
+ ["primary", page.primary],
28
+ ["complete", page.complete ?? []],
29
+ ];
30
+ for (const [field, names] of groups) {
31
+ for (const [index, name] of names.entries()) {
32
+ if (!known.has(name)) {
33
+ throw new AuditConfigError("unknown-marker", `${path}.${field}[${index}]`, `marker "${name}" is not defined in this page's markers`);
34
+ }
35
+ }
36
+ }
37
+ for (const [index, milestone] of (page.milestones ?? []).entries()) {
38
+ for (const [markerIndex, name] of milestone.markers.entries()) {
39
+ if (!known.has(name)) {
40
+ throw new AuditConfigError("unknown-marker", `${path}.milestones[${index}].markers[${markerIndex}]`, `marker "${name}" is not defined in this page's markers`);
41
+ }
42
+ }
43
+ }
44
+ }
45
+ function buildPage(page, path) {
46
+ assertMarkerNames(page, path);
47
+ assertUniqueIds((page.milestones ?? []).map((milestone, index) => ({ id: milestone.id, index })), `${path}.milestones`);
48
+ const markers = Object.fromEntries(Object.entries(page.markers).map(([name, rule]) => [
49
+ name,
50
+ normalizeMarker(rule),
51
+ ]));
52
+ return {
53
+ id: page.id,
54
+ path: page.path,
55
+ markers,
56
+ primary: page.primary,
57
+ shell: page.shell ?? [],
58
+ complete: page.complete ?? [],
59
+ milestones: (page.milestones ?? []).map((milestone) => ({
60
+ id: milestone.id,
61
+ label: milestone.label,
62
+ ...(milestone.description !== undefined ? { description: milestone.description } : {}),
63
+ markers: milestone.markers,
64
+ ...(milestone.gradeMetric !== undefined ? { gradeMetric: milestone.gradeMetric } : {}),
65
+ })),
66
+ feedbackIndicators: page.feedbackIndicators ?? [],
67
+ ...(page.fallback !== undefined ? { fallback: normalizeMarker(page.fallback) } : {}),
68
+ };
69
+ }
70
+ function mergeSettings(input) {
71
+ return {
72
+ repeats: input?.repeats ?? defaultSettings.repeats,
73
+ viewport: input?.viewport
74
+ ? { width: input.viewport.width, height: input.viewport.height }
75
+ : { ...defaultSettings.viewport },
76
+ sourceDwellMs: input?.sourceDwellMs ?? defaultSettings.sourceDwellMs,
77
+ preClickHoverMs: input?.preClickHoverMs ?? defaultSettings.preClickHoverMs,
78
+ pageObservationMs: input?.pageObservationMs ?? defaultSettings.pageObservationMs,
79
+ navigationObservationMs: input?.navigationObservationMs ?? defaultSettings.navigationObservationMs,
80
+ };
81
+ }
82
+ export function defineAudit(input) {
83
+ const parsed = auditConfigInputSchema.safeParse(input);
84
+ if (!parsed.success) {
85
+ const issue = parsed.error.issues[0];
86
+ throw new AuditConfigError("invalid-config", issue?.path.join(".") ?? "", issue?.message ?? "invalid audit config");
87
+ }
88
+ const config = parsed.data;
89
+ assertUniqueIds(config.pages, "pages");
90
+ const journeys = config.journeys ?? [];
91
+ assertUniqueIds(journeys, "journeys");
92
+ const pageIds = new Set(config.pages.map((page) => page.id));
93
+ for (const [index, journey] of journeys.entries()) {
94
+ for (const side of ["from", "to"]) {
95
+ if (!pageIds.has(journey[side])) {
96
+ throw new AuditConfigError("unknown-page", `journeys[${index}].${side}`, `page "${journey[side]}" is not defined in pages`);
97
+ }
98
+ }
99
+ }
100
+ const normalizedJourneys = journeys.map((journey) => ({
101
+ id: journey.id,
102
+ from: journey.from,
103
+ to: journey.to,
104
+ ...(journey.label !== undefined ? { label: journey.label } : {}),
105
+ }));
106
+ return deepFreeze({
107
+ origin: config.origin,
108
+ pages: config.pages.map((page, index) => buildPage(page, `pages[${index}]`)),
109
+ journeys: normalizedJourneys,
110
+ settings: mergeSettings(config.settings),
111
+ });
112
+ }
@@ -0,0 +1,6 @@
1
+ export type AuditConfigErrorCode = "invalid-config" | "duplicate-id" | "unknown-page" | "unknown-marker";
2
+ export declare class AuditConfigError extends Error {
3
+ readonly code: AuditConfigErrorCode;
4
+ readonly path: string;
5
+ constructor(code: AuditConfigErrorCode, path: string, message: string);
6
+ }
@@ -0,0 +1,10 @@
1
+ export class AuditConfigError extends Error {
2
+ code;
3
+ path;
4
+ constructor(code, path, message) {
5
+ super(path ? `${path}: ${message}` : message);
6
+ this.name = "AuditConfigError";
7
+ this.code = code;
8
+ this.path = path;
9
+ }
10
+ }
@@ -0,0 +1,3 @@
1
+ import type { MarkerInput, MarkerOptions, MarkerRule } from "./types.ts";
2
+ export declare function marker(selector: string, options?: MarkerOptions): MarkerInput;
3
+ export declare function normalizeMarker(input: MarkerInput): MarkerRule;
@@ -0,0 +1,27 @@
1
+ const DEFAULT_PATTERN_FLAGS = "i";
2
+ export function marker(selector, options = {}) {
3
+ const rule = { selector };
4
+ if (options.min !== undefined)
5
+ rule.min = options.min;
6
+ if (options.text !== undefined)
7
+ rule.text = options.text;
8
+ if (options.pattern !== undefined)
9
+ rule.pattern = options.pattern;
10
+ if (options.contains !== undefined)
11
+ rule.contains = options.contains;
12
+ return rule;
13
+ }
14
+ function normalizePattern(pattern) {
15
+ if (typeof pattern === "string")
16
+ return { source: pattern, flags: DEFAULT_PATTERN_FLAGS };
17
+ return { source: pattern.source, flags: pattern.flags };
18
+ }
19
+ export function normalizeMarker(input) {
20
+ return {
21
+ selector: input.selector,
22
+ min: input.min ?? 1,
23
+ ...(input.text !== undefined ? { text: input.text } : {}),
24
+ ...(input.pattern !== undefined ? { pattern: normalizePattern(input.pattern) } : {}),
25
+ ...(input.contains !== undefined ? { contains: input.contains.map(normalizeMarker) } : {}),
26
+ };
27
+ }
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ import type { AuditConfigInput } from "./types.ts";
3
+ export declare const auditConfigInputSchema: z.ZodType<AuditConfigInput>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ const markerInputSchema = z.lazy(() => z
3
+ .object({
4
+ selector: z.string().min(1),
5
+ min: z.number().int().positive().optional(),
6
+ text: z.string().optional(),
7
+ pattern: z.union([z.string(), z.instanceof(RegExp)]).optional(),
8
+ contains: z.array(markerInputSchema).optional(),
9
+ })
10
+ .strict());
11
+ const milestoneSchema = z
12
+ .object({
13
+ id: z.string().min(1),
14
+ label: z.string().min(1),
15
+ description: z.string().optional(),
16
+ markers: z.array(z.string().min(1)).min(1),
17
+ gradeMetric: z.enum(["feedback", "content"]).optional(),
18
+ })
19
+ .strict();
20
+ const pageSchema = z
21
+ .object({
22
+ id: z.string().min(1),
23
+ path: z
24
+ .string()
25
+ .regex(/^\/[^?#]*$/, "must be a pathname starting with / without a query string or fragment; pages are matched against location.pathname"),
26
+ markers: z.record(z.string().min(1), markerInputSchema),
27
+ primary: z.array(z.string().min(1)).min(1),
28
+ shell: z.array(z.string().min(1)).optional(),
29
+ complete: z.array(z.string().min(1)).optional(),
30
+ milestones: z.array(milestoneSchema).optional(),
31
+ fallback: markerInputSchema.optional(),
32
+ feedbackIndicators: z.array(z.string().min(1)).optional(),
33
+ })
34
+ .strict();
35
+ const journeySchema = z
36
+ .object({
37
+ id: z.string().min(1),
38
+ from: z.string().min(1),
39
+ to: z.string().min(1),
40
+ label: z.string().optional(),
41
+ })
42
+ .strict();
43
+ const settingsSchema = z
44
+ .object({
45
+ repeats: z.number().int().min(1).max(20).optional(),
46
+ viewport: z
47
+ .object({
48
+ width: z.number().int().positive(),
49
+ height: z.number().int().positive(),
50
+ })
51
+ .strict()
52
+ .optional(),
53
+ sourceDwellMs: z.number().int().nonnegative().optional(),
54
+ preClickHoverMs: z.number().int().nonnegative().optional(),
55
+ pageObservationMs: z.number().int().nonnegative().optional(),
56
+ navigationObservationMs: z.number().int().positive().optional(),
57
+ })
58
+ .strict();
59
+ export const auditConfigInputSchema = z
60
+ .object({
61
+ origin: z.url(),
62
+ pages: z.array(pageSchema).min(1),
63
+ journeys: z.array(journeySchema).optional(),
64
+ settings: settingsSchema.optional(),
65
+ })
66
+ .strict();
@@ -0,0 +1,107 @@
1
+ export interface MarkerPattern {
2
+ readonly source: string;
3
+ readonly flags: string;
4
+ }
5
+ export interface MarkerInput {
6
+ selector: string;
7
+ min?: number;
8
+ text?: string;
9
+ pattern?: string | RegExp;
10
+ contains?: MarkerInput[];
11
+ }
12
+ export interface MarkerOptions {
13
+ min?: number;
14
+ text?: string;
15
+ pattern?: string | RegExp;
16
+ contains?: MarkerInput[];
17
+ }
18
+ export interface MarkerRule {
19
+ readonly selector: string;
20
+ readonly min: number;
21
+ readonly text?: string;
22
+ readonly pattern?: MarkerPattern;
23
+ readonly contains?: readonly MarkerRule[];
24
+ }
25
+ export interface MilestoneInput {
26
+ id: string;
27
+ label: string;
28
+ description?: string;
29
+ markers: string[];
30
+ gradeMetric?: "feedback" | "content";
31
+ }
32
+ export interface MilestoneSpec {
33
+ readonly id: string;
34
+ readonly label: string;
35
+ readonly description?: string;
36
+ readonly markers: readonly string[];
37
+ readonly gradeMetric?: "feedback" | "content";
38
+ }
39
+ export interface PageInput {
40
+ id: string;
41
+ path: string;
42
+ markers: Record<string, MarkerInput>;
43
+ primary: string[];
44
+ shell?: string[];
45
+ complete?: string[];
46
+ milestones?: MilestoneInput[];
47
+ fallback?: MarkerInput;
48
+ feedbackIndicators?: string[];
49
+ }
50
+ export interface PageSpec {
51
+ readonly id: string;
52
+ readonly path: string;
53
+ readonly markers: Readonly<Record<string, MarkerRule>>;
54
+ readonly primary: readonly string[];
55
+ readonly shell: readonly string[];
56
+ readonly complete: readonly string[];
57
+ readonly milestones: readonly MilestoneSpec[];
58
+ readonly feedbackIndicators: readonly string[];
59
+ readonly fallback?: MarkerRule;
60
+ }
61
+ export interface JourneyInput {
62
+ id: string;
63
+ from: string;
64
+ to: string;
65
+ label?: string;
66
+ }
67
+ export interface JourneySpec {
68
+ readonly id: string;
69
+ readonly from: string;
70
+ readonly to: string;
71
+ readonly label?: string;
72
+ }
73
+ export interface Viewport {
74
+ readonly width: number;
75
+ readonly height: number;
76
+ }
77
+ export interface AuditSettingsInput {
78
+ repeats?: number;
79
+ viewport?: {
80
+ width: number;
81
+ height: number;
82
+ };
83
+ sourceDwellMs?: number;
84
+ preClickHoverMs?: number;
85
+ pageObservationMs?: number;
86
+ navigationObservationMs?: number;
87
+ }
88
+ export interface AuditSettings {
89
+ readonly repeats: number;
90
+ readonly viewport: Viewport;
91
+ readonly sourceDwellMs: number;
92
+ readonly preClickHoverMs: number;
93
+ readonly pageObservationMs: number;
94
+ readonly navigationObservationMs: number;
95
+ }
96
+ export interface AuditConfigInput {
97
+ origin: string;
98
+ pages: PageInput[];
99
+ journeys?: JourneyInput[];
100
+ settings?: AuditSettingsInput;
101
+ }
102
+ export interface AuditConfig {
103
+ readonly origin: string;
104
+ readonly pages: readonly PageSpec[];
105
+ readonly journeys: readonly JourneySpec[];
106
+ readonly settings: AuditSettings;
107
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ export declare function portableArtifactPath(path: any): {
2
+ path: string;
3
+ mediaType: any;
4
+ } | null;
5
+ export declare function referencedArtifacts(audit: any): any[];
6
+ export declare function buildArtifactManifest(directory: any, audit: any): Promise<{
7
+ version: number;
8
+ pathSemantics: string;
9
+ files: any[];
10
+ missing: any[];
11
+ }>;