@forkpoint/agent-lighthouse-core 3.1.0 → 4.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.
- package/dist/index.d.mts +398 -79
- package/dist/index.d.ts +398 -79
- package/dist/index.js +6789 -3630
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6773 -3621
- package/dist/index.mjs.map +1 -1
- package/migration-map.json +255 -129
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -2,12 +2,13 @@ import { Dispatcher } from 'undici';
|
|
|
2
2
|
import { CheerioAPI } from 'cheerio';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
|
+
declare function isSafeUrl(url: string): Promise<boolean>;
|
|
5
6
|
interface FetchOptions {
|
|
6
7
|
url: string;
|
|
7
8
|
timeout?: number;
|
|
8
9
|
followRedirects?: boolean;
|
|
9
10
|
acceptHeader?: string;
|
|
10
|
-
method?:
|
|
11
|
+
method?: "GET" | "POST" | "OPTIONS" | "HEAD" | "DELETE";
|
|
11
12
|
body?: string;
|
|
12
13
|
contentType?: string;
|
|
13
14
|
/** Override the User-Agent header (e.g. to probe a site as a specific AI bot). */
|
|
@@ -57,11 +58,6 @@ interface FetchResult {
|
|
|
57
58
|
}>;
|
|
58
59
|
error?: string;
|
|
59
60
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Validates that a URL is safe to fetch (http/https scheme, non-private IP).
|
|
62
|
-
* Use before fetching any URL extracted from scanned site content.
|
|
63
|
-
*/
|
|
64
|
-
declare function isSafeUrl(url: string): Promise<boolean>;
|
|
65
61
|
interface FetcherOptions {
|
|
66
62
|
/**
|
|
67
63
|
* undici dispatcher for every request this fetcher makes.
|
|
@@ -89,6 +85,10 @@ interface FetcherOptions {
|
|
|
89
85
|
* is the origin.
|
|
90
86
|
*/
|
|
91
87
|
maxConcurrent?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Extra HTTP headers sent with every request from this fetcher.
|
|
90
|
+
*/
|
|
91
|
+
headers?: Record<string, string>;
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
94
|
* A dispatcher that opens at most `connections` sockets per origin.
|
|
@@ -105,7 +105,7 @@ declare function createFetcher(fetcherOptions?: FetcherOptions): {
|
|
|
105
105
|
|
|
106
106
|
interface WafProtection {
|
|
107
107
|
isBlocked: boolean;
|
|
108
|
-
provider?:
|
|
108
|
+
provider?: "akamai" | "cloudflare" | "datadome" | "perimeterx" | "imperva" | "kasada" | "aws-waf" | "generic-waf" | "connection-drop" | "rate-limited";
|
|
109
109
|
name: string;
|
|
110
110
|
reason: string;
|
|
111
111
|
statusCode?: number;
|
|
@@ -127,7 +127,7 @@ interface WafProtection {
|
|
|
127
127
|
*/
|
|
128
128
|
declare function detectWafProtection(targetUrl: string, homepageResult: FetchResult | null, rootFiles: Record<string, FetchResult>, scannedPagesCount: number): WafProtection | null;
|
|
129
129
|
|
|
130
|
-
type PageType =
|
|
130
|
+
type PageType = "homepage" | "category" | "product" | "content";
|
|
131
131
|
declare const PAGE_TYPE_LABELS: Record<PageType, string>;
|
|
132
132
|
/**
|
|
133
133
|
* A user-supplied page to scan with an explicit type.
|
|
@@ -137,7 +137,7 @@ interface PageOverride {
|
|
|
137
137
|
pageType: PageType;
|
|
138
138
|
}
|
|
139
139
|
/** Per-field presence in a product page's structured data. */
|
|
140
|
-
type FieldStatus =
|
|
140
|
+
type FieldStatus = "found" | "partial" | "missing";
|
|
141
141
|
/**
|
|
142
142
|
* Field-level verification of a product page, read directly from its structured
|
|
143
143
|
* data (JSON-LD + Microdata + RDFa).
|
|
@@ -153,7 +153,7 @@ interface ProductFieldVerification {
|
|
|
153
153
|
reviewCount: FieldStatus;
|
|
154
154
|
sourceUrl?: string;
|
|
155
155
|
}
|
|
156
|
-
type FixEffort =
|
|
156
|
+
type FixEffort = "trivial" | "easy" | "moderate" | "complex";
|
|
157
157
|
interface AuditGuidance {
|
|
158
158
|
/** Customer-facing explanation of business impact when this audit fails */
|
|
159
159
|
impact: string;
|
|
@@ -168,7 +168,7 @@ interface AuditGuidance {
|
|
|
168
168
|
/** Tags for filtering/grouping in the report UI */
|
|
169
169
|
tags?: string[];
|
|
170
170
|
}
|
|
171
|
-
type ScoreDisplayMode =
|
|
171
|
+
type ScoreDisplayMode = "binary" | "ternary" | "informative";
|
|
172
172
|
/** Public sunset notice for a deprecated audit (see docs/evidence/sunset/not-a-factor.md). */
|
|
173
173
|
interface DeprecationNotice {
|
|
174
174
|
/** One sentence: why this signal is not a factor. */
|
|
@@ -180,12 +180,12 @@ interface DeprecationNotice {
|
|
|
180
180
|
* Strength of the published evidence backing an audit, assigned in the audit's
|
|
181
181
|
* dossier per docs/evidence/policy.md. Only A and B carry scoring weight.
|
|
182
182
|
*/
|
|
183
|
-
type EvidenceGrade =
|
|
183
|
+
type EvidenceGrade = "A" | "B" | "C" | "D";
|
|
184
184
|
/**
|
|
185
185
|
* How an audit participates in scoring. Derived from its evidence grade
|
|
186
186
|
* (spec §4): only `scored` audits move a category score.
|
|
187
187
|
*/
|
|
188
|
-
type AuditTier =
|
|
188
|
+
type AuditTier = "scored" | "informative" | "experimental";
|
|
189
189
|
interface AuditMeta {
|
|
190
190
|
id: string;
|
|
191
191
|
category: string;
|
|
@@ -194,6 +194,7 @@ interface AuditMeta {
|
|
|
194
194
|
description: string;
|
|
195
195
|
scoreDisplayMode: ScoreDisplayMode;
|
|
196
196
|
weight: number;
|
|
197
|
+
pageTypes?: PageType[];
|
|
197
198
|
applicablePageTypes?: PageType[];
|
|
198
199
|
defaultPriority: CheckPriority;
|
|
199
200
|
guidance?: AuditGuidance;
|
|
@@ -223,7 +224,7 @@ interface AuditMeta {
|
|
|
223
224
|
* Declared here rather than in `scan-evidence.ts` so `AuditMeta` can name it
|
|
224
225
|
* without the audit layer importing the scan layer.
|
|
225
226
|
*/
|
|
226
|
-
type EvidenceKey =
|
|
227
|
+
type EvidenceKey = "origin-reachable" | "unblocked-fetches" | "rendered-body" | "sample-adequate";
|
|
227
228
|
interface AuditResult {
|
|
228
229
|
status: CheckStatus;
|
|
229
230
|
score: number;
|
|
@@ -248,8 +249,8 @@ interface AuditResult {
|
|
|
248
249
|
*/
|
|
249
250
|
remediation?: string;
|
|
250
251
|
}
|
|
251
|
-
type CheckStatus =
|
|
252
|
-
type CheckPriority =
|
|
252
|
+
type CheckStatus = "pass" | "warn" | "fail" | "na";
|
|
253
|
+
type CheckPriority = "critical" | "high" | "medium" | "low";
|
|
253
254
|
interface CheckRecommendation {
|
|
254
255
|
priority: CheckPriority;
|
|
255
256
|
description: string;
|
|
@@ -298,8 +299,10 @@ interface CategoryResult {
|
|
|
298
299
|
passCount: number;
|
|
299
300
|
warnCount: number;
|
|
300
301
|
failCount: number;
|
|
302
|
+
registryMass?: number;
|
|
303
|
+
assessedMass?: number;
|
|
301
304
|
}
|
|
302
|
-
type ScoreTier =
|
|
305
|
+
type ScoreTier = "agent-ready" | "partially-ready" | "needs-work" | "not-ready";
|
|
303
306
|
/**
|
|
304
307
|
* Whether a verdict about this site can mean anything, and what is missing.
|
|
305
308
|
*
|
|
@@ -349,6 +352,47 @@ interface ScanReport {
|
|
|
349
352
|
readinessVitals?: ReadinessVitals;
|
|
350
353
|
productFields?: ProductFieldVerification;
|
|
351
354
|
wafProtection?: WafProtection;
|
|
355
|
+
originEvidence?: {
|
|
356
|
+
origin: string;
|
|
357
|
+
version: string;
|
|
358
|
+
readAt: string;
|
|
359
|
+
cached: boolean;
|
|
360
|
+
};
|
|
361
|
+
conditions?: ScanConditions;
|
|
362
|
+
}
|
|
363
|
+
interface ScanConditions {
|
|
364
|
+
url: string;
|
|
365
|
+
pageType: {
|
|
366
|
+
type: PageType;
|
|
367
|
+
source: "declared" | "detected";
|
|
368
|
+
};
|
|
369
|
+
origin: {
|
|
370
|
+
origin: string;
|
|
371
|
+
version: string;
|
|
372
|
+
readAt: string;
|
|
373
|
+
cached: boolean;
|
|
374
|
+
};
|
|
375
|
+
coverage: {
|
|
376
|
+
registryMass: number;
|
|
377
|
+
assessedMass: number;
|
|
378
|
+
pageMass: number;
|
|
379
|
+
originMass: number;
|
|
380
|
+
gatedMass: number;
|
|
381
|
+
};
|
|
382
|
+
unscored: {
|
|
383
|
+
totalCount: number;
|
|
384
|
+
informativeCount: number;
|
|
385
|
+
gatedCount: number;
|
|
386
|
+
reasons: Record<string, number>;
|
|
387
|
+
};
|
|
388
|
+
/** The wall-clock budget the scan ran under, and whether it ran out. */
|
|
389
|
+
budget?: {
|
|
390
|
+
limitMs: number;
|
|
391
|
+
elapsedMs: number;
|
|
392
|
+
exhausted: boolean;
|
|
393
|
+
/** Audits reported `na` because the budget ran out before they started. */
|
|
394
|
+
skippedCount: number;
|
|
395
|
+
};
|
|
352
396
|
}
|
|
353
397
|
interface ReadinessVitals {
|
|
354
398
|
commerce: number;
|
|
@@ -357,6 +401,54 @@ interface ReadinessVitals {
|
|
|
357
401
|
technical: number;
|
|
358
402
|
}
|
|
359
403
|
|
|
404
|
+
interface OriginCacheOptions {
|
|
405
|
+
bypassOriginCache?: boolean;
|
|
406
|
+
headers?: Record<string, string>;
|
|
407
|
+
}
|
|
408
|
+
interface OriginEvidence {
|
|
409
|
+
origin: string;
|
|
410
|
+
version: string;
|
|
411
|
+
readAt: string;
|
|
412
|
+
rootFiles: Record<string, FetchResult>;
|
|
413
|
+
originHomepage?: FetchResult;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Derives a canonical anonymous origin cache key.
|
|
417
|
+
*
|
|
418
|
+
* Strips any userinfo/credentials from the URL so credentials never leak into
|
|
419
|
+
* cache keys. Request headers other than credentials are folded in as a
|
|
420
|
+
* fingerprint: a scan that sets a bot user agent must not share a slot with
|
|
421
|
+
* a default scan, since the origin may answer the two differently.
|
|
422
|
+
*/
|
|
423
|
+
declare function computeOriginCacheKey(url: string, version?: string, headers?: Record<string, string>): string;
|
|
424
|
+
/**
|
|
425
|
+
* Determines whether the scan must bypass the shared origin cache.
|
|
426
|
+
* Authenticated scans (URL credentials, Authorization header, cookies) or explicit bypass flags bypass the shared cache.
|
|
427
|
+
*/
|
|
428
|
+
declare function shouldBypassOriginCache(url: string, options?: OriginCacheOptions): boolean;
|
|
429
|
+
/**
|
|
430
|
+
* A bounded, TTL-evicting store of origin evidence.
|
|
431
|
+
*
|
|
432
|
+
* Expired entries are swept on every write, and the oldest entry is dropped
|
|
433
|
+
* when the store is full, so a process that scans many origins once each
|
|
434
|
+
* cannot grow without limit. A read of an expired key evicts it as well.
|
|
435
|
+
*/
|
|
436
|
+
declare class OriginCache {
|
|
437
|
+
private cache;
|
|
438
|
+
private ttlMs;
|
|
439
|
+
private maxEntries;
|
|
440
|
+
constructor(ttlMs?: number, maxEntries?: number);
|
|
441
|
+
/** Drop every entry whose TTL has passed. */
|
|
442
|
+
sweep(now?: number): void;
|
|
443
|
+
get(key: string): OriginEvidence | undefined;
|
|
444
|
+
has(key: string): boolean;
|
|
445
|
+
set(key: string, evidence: OriginEvidence, ttlMs?: number): void;
|
|
446
|
+
delete(key: string): boolean;
|
|
447
|
+
clear(): void;
|
|
448
|
+
get size(): number;
|
|
449
|
+
}
|
|
450
|
+
declare const defaultOriginCache: OriginCache;
|
|
451
|
+
|
|
360
452
|
/**
|
|
361
453
|
* What a scan actually obtained, decided once, before any audit runs.
|
|
362
454
|
*
|
|
@@ -394,7 +486,7 @@ interface A11yNodeFinding {
|
|
|
394
486
|
target: string;
|
|
395
487
|
summary: string;
|
|
396
488
|
}
|
|
397
|
-
type A11yStatus =
|
|
489
|
+
type A11yStatus = "pass" | "fail" | "incomplete" | "inapplicable";
|
|
398
490
|
interface A11yRuleResult {
|
|
399
491
|
status: A11yStatus;
|
|
400
492
|
nodes: A11yNodeFinding[];
|
|
@@ -405,6 +497,7 @@ type A11yPageResult = Record<string, A11yRuleResult>;
|
|
|
405
497
|
interface PageContext {
|
|
406
498
|
url: string;
|
|
407
499
|
pageType: PageType;
|
|
500
|
+
pageTypeSource?: "declared" | "detected";
|
|
408
501
|
fetchResult: FetchResult;
|
|
409
502
|
$: CheerioAPI;
|
|
410
503
|
/** Parsed JSON-LD blocks only (used by JSON-LD-specific audits). */
|
|
@@ -437,6 +530,15 @@ interface CheckContext {
|
|
|
437
530
|
baseUrl: string;
|
|
438
531
|
fetch: (options: FetchOptions) => Promise<FetchResult>;
|
|
439
532
|
wafProtection?: WafProtection;
|
|
533
|
+
/**
|
|
534
|
+
* The object per-scan gatherer caches key on.
|
|
535
|
+
*
|
|
536
|
+
* The runner hands each audit a scoped copy of this context, and a copy has
|
|
537
|
+
* a new identity. Without this stamp every gatherer `WeakMap` would miss
|
|
538
|
+
* once per audit and repeat its fetch. The runner sets it on each copy;
|
|
539
|
+
* an unstamped context is its own owner. See `gatherers/cache-owner.ts`.
|
|
540
|
+
*/
|
|
541
|
+
cacheOwner?: object;
|
|
440
542
|
/**
|
|
441
543
|
* What the scan actually obtained, decided once before any audit ran.
|
|
442
544
|
*
|
|
@@ -445,6 +547,16 @@ interface CheckContext {
|
|
|
445
547
|
* harnesses that do not exercise the gate pass `allEvidenceMet()`.
|
|
446
548
|
*/
|
|
447
549
|
evidence: ScanEvidence;
|
|
550
|
+
/**
|
|
551
|
+
* Origin evidence metadata and cached homepage response.
|
|
552
|
+
*/
|
|
553
|
+
originEvidence?: {
|
|
554
|
+
origin: string;
|
|
555
|
+
version: string;
|
|
556
|
+
readAt: string;
|
|
557
|
+
cached: boolean;
|
|
558
|
+
originHomepage?: FetchResult;
|
|
559
|
+
};
|
|
448
560
|
}
|
|
449
561
|
type CheckFn = (ctx: CheckContext) => CheckResult | Promise<CheckResult>;
|
|
450
562
|
|
|
@@ -498,7 +610,7 @@ declare abstract class Audit {
|
|
|
498
610
|
[key: string]: unknown;
|
|
499
611
|
} | string, pageUrl?: string): AuditResult;
|
|
500
612
|
/** Merge static meta with the runtime result to produce a CheckResult. */
|
|
501
|
-
toCheckResult(rawResult: AuditResult): CheckResult;
|
|
613
|
+
toCheckResult(rawResult: AuditResult, overrideDisplayMode?: ScoreDisplayMode): CheckResult;
|
|
502
614
|
}
|
|
503
615
|
|
|
504
616
|
interface CategoryConfig {
|
|
@@ -571,9 +683,10 @@ interface AuditTrace {
|
|
|
571
683
|
* `ran` — the audit executed and returned.
|
|
572
684
|
* `skipped` — no scanned page matched its `applicablePageTypes`.
|
|
573
685
|
* `gated` — the scan never obtained evidence the audit needs.
|
|
686
|
+
* `budget` — the scan's wall-clock budget ran out before it started.
|
|
574
687
|
* `error` — it threw, or its result was rejected by the schema.
|
|
575
688
|
*/
|
|
576
|
-
outcome:
|
|
689
|
+
outcome: "ran" | "skipped" | "gated" | "budget" | "error";
|
|
577
690
|
status: CheckStatus;
|
|
578
691
|
score: number;
|
|
579
692
|
weight: number;
|
|
@@ -585,10 +698,10 @@ interface AuditTrace {
|
|
|
585
698
|
explanation?: string;
|
|
586
699
|
pageUrl?: string;
|
|
587
700
|
/** The structured evidence behind the verdict, as the report carries it. */
|
|
588
|
-
details?: CheckResult[
|
|
701
|
+
details?: CheckResult["details"];
|
|
589
702
|
}
|
|
590
703
|
/** Which outcome a finished check represents. */
|
|
591
|
-
declare function outcomeOf(check: CheckResult): AuditTrace[
|
|
704
|
+
declare function outcomeOf(check: CheckResult): AuditTrace["outcome"];
|
|
592
705
|
/** Build a trace record from a finished check. */
|
|
593
706
|
declare function traceFromCheck(check: CheckResult, durationMs: number): AuditTrace;
|
|
594
707
|
/** One trace as a log line: the shape a human scans, not the full record. */
|
|
@@ -604,10 +717,10 @@ interface AuditRunResult {
|
|
|
604
717
|
* ProgressTracker, which owns counting and fraction/elapsed stamping.
|
|
605
718
|
*/
|
|
606
719
|
type AuditProgressEvent = {
|
|
607
|
-
type:
|
|
720
|
+
type: "unit:done";
|
|
608
721
|
label: string;
|
|
609
722
|
} | {
|
|
610
|
-
type:
|
|
723
|
+
type: "unit:fail";
|
|
611
724
|
label: string;
|
|
612
725
|
error: string;
|
|
613
726
|
};
|
|
@@ -620,53 +733,69 @@ type AuditProgressEvent = {
|
|
|
620
733
|
*/
|
|
621
734
|
type AuditTraceHandler = (trace: AuditTrace) => void;
|
|
622
735
|
interface AuditPlan {
|
|
623
|
-
runnable:
|
|
624
|
-
reg: AuditRegistration;
|
|
625
|
-
categoryId: string;
|
|
626
|
-
}>;
|
|
736
|
+
runnable: RunnableAudit[];
|
|
627
737
|
skipped: CheckResult[];
|
|
628
738
|
}
|
|
629
739
|
/** How `planAudits` should treat audits the scan cannot feed. */
|
|
630
740
|
interface PlanOptions {
|
|
631
741
|
/**
|
|
632
|
-
* Skip audits whose `requires` the scan did not obtain.
|
|
742
|
+
* Skip audits whose `requires` the scan did not obtain. **Defaults to true.**
|
|
633
743
|
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* against an ungated one.
|
|
744
|
+
* An audit's `requires` decides what a blocked or client-rendered scan
|
|
745
|
+
* reports, so a caller that omits this option gets the gated set — the same
|
|
746
|
+
* set a scan gets. A production diagnostic may pass `false` to bypass only
|
|
747
|
+
* these per-audit `requires` checks. It is never the default, and it never
|
|
748
|
+
* bypasses the unconditional unread-scan guard.
|
|
640
749
|
*/
|
|
641
750
|
enforceEvidence?: boolean;
|
|
642
751
|
}
|
|
752
|
+
interface RunnableAudit {
|
|
753
|
+
reg: AuditRegistration;
|
|
754
|
+
categoryId: string;
|
|
755
|
+
scopedPages?: PageContext[];
|
|
756
|
+
scoreDisplayMode?: ScoreDisplayMode;
|
|
757
|
+
}
|
|
643
758
|
/**
|
|
644
759
|
* Split a scan config into the audits that will actually execute and the
|
|
645
760
|
* `na` stubs for those it will not. Exported so the orchestrator can size the
|
|
646
761
|
* audits progress phase before running it.
|
|
647
762
|
*/
|
|
648
|
-
declare function planAudits(ctx: CheckContext, config: ScanConfig, options?: PlanOptions):
|
|
763
|
+
declare function planAudits(ctx: CheckContext, config: ScanConfig, options?: PlanOptions): {
|
|
764
|
+
runnable: RunnableAudit[];
|
|
765
|
+
skipped: CheckResult[];
|
|
766
|
+
};
|
|
767
|
+
/** A budget as a sentence names it: whole seconds, or milliseconds under one. */
|
|
768
|
+
declare function formatBudget(ms: number): string;
|
|
769
|
+
/** What an aborted budget signal says, for the stub that names it. */
|
|
770
|
+
declare function budgetReason(signal: AbortSignal): string;
|
|
649
771
|
/**
|
|
650
772
|
* Execute all audits registered in the config against the scan context.
|
|
651
773
|
* Returns check results grouped into categories with weighted scores.
|
|
652
774
|
* Pass a precomputed `plan` (from {@link planAudits}) to avoid recomputing it.
|
|
775
|
+
*
|
|
776
|
+
* `budget` is the scan's wall-clock budget. Once it is aborted, no further
|
|
777
|
+
* audit is constructed, and none that was still running is believed: both
|
|
778
|
+
* report `na` tagged {@link TAG_SKIPPED_SCAN_BUDGET}. The running one is
|
|
779
|
+
* withheld because a request the budget refused answers with an error, and
|
|
780
|
+
* an audit reads that error as a broken link or a missing artifact. That
|
|
781
|
+
* would be a claim about the clock, not about the site.
|
|
653
782
|
*/
|
|
654
|
-
declare function runAudits(ctx: CheckContext, config: ScanConfig, onEvent?: (event: AuditProgressEvent) => void, plan?: AuditPlan, onTrace?: AuditTraceHandler): Promise<AuditRunResult>;
|
|
783
|
+
declare function runAudits(ctx: CheckContext, config: ScanConfig, onEvent?: (event: AuditProgressEvent) => void, plan?: AuditPlan, onTrace?: AuditTraceHandler, budget?: AbortSignal): Promise<AuditRunResult>;
|
|
655
784
|
|
|
656
|
-
type PhaseId =
|
|
785
|
+
type PhaseId = "fetch-root" | "fetch-pages" | "analyze" | "audits" | "report";
|
|
657
786
|
type ScanEvent = {
|
|
658
|
-
type:
|
|
787
|
+
type: "scan:start";
|
|
659
788
|
url: string;
|
|
660
789
|
fraction: number;
|
|
661
790
|
elapsedMs: number;
|
|
662
791
|
} | {
|
|
663
|
-
type:
|
|
792
|
+
type: "phase:start";
|
|
664
793
|
phase: PhaseId;
|
|
665
794
|
totalUnits: number;
|
|
666
795
|
fraction: number;
|
|
667
796
|
elapsedMs: number;
|
|
668
797
|
} | {
|
|
669
|
-
type:
|
|
798
|
+
type: "unit:done";
|
|
670
799
|
phase: PhaseId;
|
|
671
800
|
completed: number;
|
|
672
801
|
total: number;
|
|
@@ -674,20 +803,20 @@ type ScanEvent = {
|
|
|
674
803
|
fraction: number;
|
|
675
804
|
elapsedMs: number;
|
|
676
805
|
} | {
|
|
677
|
-
type:
|
|
806
|
+
type: "unit:fail";
|
|
678
807
|
phase: PhaseId;
|
|
679
808
|
label: string;
|
|
680
809
|
error: string;
|
|
681
810
|
fraction: number;
|
|
682
811
|
elapsedMs: number;
|
|
683
812
|
} | {
|
|
684
|
-
type:
|
|
813
|
+
type: "phase:done";
|
|
685
814
|
phase: PhaseId;
|
|
686
815
|
durationMs: number;
|
|
687
816
|
fraction: number;
|
|
688
817
|
elapsedMs: number;
|
|
689
818
|
} | {
|
|
690
|
-
type:
|
|
819
|
+
type: "scan:done";
|
|
691
820
|
durationMs: number;
|
|
692
821
|
/** Null when the scan obtained too little evidence to judge the site. */
|
|
693
822
|
score: number | null;
|
|
@@ -734,7 +863,22 @@ declare class ProgressTracker {
|
|
|
734
863
|
interface ScanOptions {
|
|
735
864
|
onEvent?: (event: ScanEvent) => void;
|
|
736
865
|
pages?: PageOverride[] | null;
|
|
866
|
+
/** Explicitly declared page type for the target URL. */
|
|
867
|
+
pageType?: PageType;
|
|
868
|
+
/**
|
|
869
|
+
* The caller's cancellation. Aborting it makes `runScan` throw; the scan
|
|
870
|
+
* budget below never does.
|
|
871
|
+
*/
|
|
737
872
|
signal?: AbortSignal;
|
|
873
|
+
/**
|
|
874
|
+
* Wall-clock budget for the whole scan, in milliseconds. Defaults to
|
|
875
|
+
* {@link SCAN_TIMEOUT_MS}. When it runs out the scan finishes with what it
|
|
876
|
+
* has: requests in flight abort, no further request is sent, and every
|
|
877
|
+
* audit not yet started, or still running when it went, reports `na`
|
|
878
|
+
* tagged `skipped:scan-budget`. `conditions.budget` on the report records
|
|
879
|
+
* it. `0` disables the budget.
|
|
880
|
+
*/
|
|
881
|
+
timeoutMs?: number;
|
|
738
882
|
/**
|
|
739
883
|
* Restrict the scan to these category ids. Unknown ids simply match nothing —
|
|
740
884
|
* validate them at the entry point so the operator hears about a typo.
|
|
@@ -757,48 +901,41 @@ interface ScanOptions {
|
|
|
757
901
|
*
|
|
758
902
|
* On by default. An audit whose required evidence the scan never obtained
|
|
759
903
|
* reports `na` tagged `skipped:no-evidence`, with the reason attached, and
|
|
760
|
-
* is never constructed. Set it to `false` to
|
|
761
|
-
*
|
|
904
|
+
* is never constructed. Set it to `false` to bypass only the per-audit
|
|
905
|
+
* `requires` checks. The unread-scan guard remains unconditional, so a scan
|
|
906
|
+
* that read no attributable site response still runs no audit.
|
|
762
907
|
*/
|
|
763
908
|
enforceEvidenceGate?: boolean;
|
|
764
909
|
/**
|
|
765
910
|
* undici dispatcher for every request this scan makes.
|
|
766
|
-
*
|
|
767
|
-
* Omitted, the scan uses the fetcher's shared agent, which opens as many
|
|
768
|
-
* connections per origin as the scan asks for. A caller scanning origins that
|
|
769
|
-
* did not invite it — the nightly corpus job — passes a bounded agent so the
|
|
770
|
-
* ~28 root-file requests the scan issues at once do not arrive at a stranger's
|
|
771
|
-
* WAF as a burst.
|
|
772
911
|
*/
|
|
773
912
|
dispatcher?: Dispatcher;
|
|
774
913
|
/**
|
|
775
914
|
* How many requests this scan may have in flight at once.
|
|
776
|
-
*
|
|
777
|
-
* Omitted, the scan issues every request as it reaches the fetcher. A caller
|
|
778
|
-
* scanning origins that did not invite it sets this alongside `dispatcher`:
|
|
779
|
-
* the dispatcher bounds the sockets, and this bounds what is issued, so the
|
|
780
|
-
* requests the scan holds back wait outside the per-request deadline and
|
|
781
|
-
* outside `ttfbMs` instead of inside undici's queue. Without it a bounded
|
|
782
|
-
* scan reports its own queueing as the origin being slow or unreachable.
|
|
783
915
|
*/
|
|
784
916
|
maxConcurrent?: number;
|
|
917
|
+
/**
|
|
918
|
+
* Extra HTTP request headers to pass on all fetches.
|
|
919
|
+
*/
|
|
920
|
+
headers?: Record<string, string>;
|
|
921
|
+
/**
|
|
922
|
+
* Explicitly bypass the shared origin evidence cache for this scan.
|
|
923
|
+
*/
|
|
924
|
+
bypassOriginCache?: boolean;
|
|
925
|
+
/**
|
|
926
|
+
* Optional custom OriginCache instance (defaults to defaultOriginCache).
|
|
927
|
+
*/
|
|
928
|
+
originCache?: OriginCache;
|
|
785
929
|
/**
|
|
786
930
|
* A `robots.txt` response the caller already has, used instead of fetching
|
|
787
931
|
* it again.
|
|
788
|
-
*
|
|
789
|
-
* For a caller that must read `robots.txt` before it decides to scan at all.
|
|
790
|
-
* The nightly corpus job is one: it asks permission first, and without this
|
|
791
|
-
* every site it visits gets two requests for the one file its owner watches.
|
|
792
|
-
* It must be the response to `<baseUrl>/robots.txt` fetched with this
|
|
793
|
-
* scanner's own user agent — anything else and the scan judges a file it was
|
|
794
|
-
* not served.
|
|
795
932
|
*/
|
|
796
933
|
robotsTxt?: FetchResult;
|
|
797
934
|
}
|
|
798
935
|
declare function runScan(url: string, options?: ScanOptions): Promise<ScanReport>;
|
|
799
936
|
|
|
800
|
-
type FetchClass =
|
|
801
|
-
type ExpectedKind =
|
|
937
|
+
type FetchClass = "ok" | "soft-404" | "blocked" | "missing" | "error";
|
|
938
|
+
type ExpectedKind = "text" | "json" | "xml" | "html";
|
|
802
939
|
declare function stripBom(text: string): string;
|
|
803
940
|
declare function normalizeNewlines(text: string): string;
|
|
804
941
|
/**
|
|
@@ -814,7 +951,7 @@ declare function classifyFetch(result: FetchResult | undefined, expected: Expect
|
|
|
814
951
|
declare function isRealFile(result: FetchResult | undefined, expected: ExpectedKind): boolean;
|
|
815
952
|
|
|
816
953
|
interface RobotsRule {
|
|
817
|
-
type:
|
|
954
|
+
type: "allow" | "disallow";
|
|
818
955
|
path: string;
|
|
819
956
|
}
|
|
820
957
|
interface RobotsGroup {
|
|
@@ -888,7 +1025,7 @@ declare const BASELINE_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) App
|
|
|
888
1025
|
* rate limit each need a different remedy from the operator, and an opaque 403
|
|
889
1026
|
* may even be correct impersonation defence.
|
|
890
1027
|
*/
|
|
891
|
-
type BlockClass =
|
|
1028
|
+
type BlockClass = "ok" | "cf-challenge" | "pay-per-crawl" | "anubis-pow" | "rate-limited" | "opaque-403" | "soft-block" | "transport-error";
|
|
892
1029
|
interface UaProbe {
|
|
893
1030
|
url: string;
|
|
894
1031
|
token: string;
|
|
@@ -955,6 +1092,10 @@ interface SitemapTree {
|
|
|
955
1092
|
malformedLastmod: number;
|
|
956
1093
|
/** True when a cap stopped the walk, so `entries` is not the whole tree. */
|
|
957
1094
|
truncated: boolean;
|
|
1095
|
+
/** Sitemap files that answered 200 and parsed as a urlset or sitemapindex. */
|
|
1096
|
+
readableFiles: string[];
|
|
1097
|
+
/** Sitemap files that answered 200 but were neither. A soft-404 lands here. */
|
|
1098
|
+
malformedFiles: string[];
|
|
958
1099
|
}
|
|
959
1100
|
/**
|
|
960
1101
|
* Does this value parse as a W3C Datetime, the format the sitemap protocol
|
|
@@ -969,6 +1110,11 @@ declare function isW3CDateTime(value: string): boolean;
|
|
|
969
1110
|
/**
|
|
970
1111
|
* Walk a site's sitemap roots and collect their `<url>` rows.
|
|
971
1112
|
*
|
|
1113
|
+
* Every root in `roots` is read: a robots.txt that declares three sitemaps
|
|
1114
|
+
* has three, and stopping at the first would judge a third of the site as
|
|
1115
|
+
* the whole. `fallbackRoots` are the conventional paths, probed in order only
|
|
1116
|
+
* when no declared root parsed, and the first one that does ends the probe.
|
|
1117
|
+
*
|
|
972
1118
|
* Recursion stops after one level of `<sitemapindex>`: the depth of a nested
|
|
973
1119
|
* index is chosen by the site being scanned, so following it arbitrarily is an
|
|
974
1120
|
* unbounded walk driven by untrusted input. Every child URL is `isSafeUrl`- and
|
|
@@ -978,6 +1124,7 @@ declare function collectSitemapEntries(fetch: (options: FetchOptions) => Promise
|
|
|
978
1124
|
maxChildren?: number;
|
|
979
1125
|
maxEntries?: number;
|
|
980
1126
|
signal?: AbortSignal;
|
|
1127
|
+
fallbackRoots?: string[];
|
|
981
1128
|
}): Promise<SitemapTree>;
|
|
982
1129
|
/**
|
|
983
1130
|
* Take an even-strided sample of `n` entries.
|
|
@@ -997,7 +1144,7 @@ interface CssRule {
|
|
|
997
1144
|
/** The enclosing at-rule prelude (`media print`, `supports (...)`), if any. */
|
|
998
1145
|
atRule?: string;
|
|
999
1146
|
/** Where the rule came from, for evidence. */
|
|
1000
|
-
origin:
|
|
1147
|
+
origin: "inline" | string;
|
|
1001
1148
|
}
|
|
1002
1149
|
/**
|
|
1003
1150
|
* Scan a stylesheet into flat selector/declaration pairs.
|
|
@@ -1162,17 +1309,35 @@ declare function extractStylesheetUrls($: CheerioAPI): string[];
|
|
|
1162
1309
|
*/
|
|
1163
1310
|
declare function detectPageType(url: string, $: CheerioAPI, jsonLd: object[], meta: Record<string, string>, isFirstPage: boolean): PageType;
|
|
1164
1311
|
|
|
1165
|
-
declare const DEFAULT_SCAN_LIMIT =
|
|
1166
|
-
declare const MAX_PAGES_PER_SCAN =
|
|
1312
|
+
declare const DEFAULT_SCAN_LIMIT = 1;
|
|
1313
|
+
declare const MAX_PAGES_PER_SCAN = 1;
|
|
1314
|
+
declare const ORIGIN_EVIDENCE_VERSION = "v1";
|
|
1315
|
+
declare const DEFAULT_ORIGIN_CACHE_TTL_MS: number;
|
|
1316
|
+
/**
|
|
1317
|
+
* How many origins the shared cache holds at once. Each entry carries every
|
|
1318
|
+
* root file of one origin, so a long-lived process (the MCP server, a looped
|
|
1319
|
+
* live run) needs a ceiling, not only a TTL.
|
|
1320
|
+
*/
|
|
1321
|
+
declare const DEFAULT_ORIGIN_CACHE_MAX_ENTRIES = 256;
|
|
1167
1322
|
declare const REQUEST_TIMEOUT_MS = 10000;
|
|
1168
|
-
|
|
1323
|
+
/**
|
|
1324
|
+
* Wall-clock budget for one scan. When it runs out, requests in flight are
|
|
1325
|
+
* aborted, no further request is sent, and every audit not yet started is
|
|
1326
|
+
* reported `na` tagged `skipped:scan-budget`. 180 s clears the 95th
|
|
1327
|
+
* percentile of the curated corpus (109 s on 2026-09-02) with margin; the
|
|
1328
|
+
* scans it cuts ran 5 to 17 minutes.
|
|
1329
|
+
*/
|
|
1330
|
+
declare const SCAN_TIMEOUT_MS = 180000;
|
|
1169
1331
|
declare const MAX_RESPONSE_BODY_BYTES: number;
|
|
1332
|
+
/** @deprecated Unused internally; retained for published API stability. Scheduled for removal in v4. */
|
|
1170
1333
|
declare const MAX_CONCURRENT_REQUESTS = 10;
|
|
1171
1334
|
declare const SCANNER_USER_AGENT = "AgentLighthouse/1.0 (+https://github.com/ForkPoint/agent-lighthouse)";
|
|
1172
1335
|
declare const TAG_SKIPPED_PAGE_TYPE = "skipped:page-type";
|
|
1173
1336
|
declare const TAG_SCAN_ERROR = "scan-error";
|
|
1174
1337
|
/** An audit the scan could not feed: it needs evidence this scan never got. */
|
|
1175
1338
|
declare const TAG_SKIPPED_NO_EVIDENCE = "skipped:no-evidence";
|
|
1339
|
+
/** An audit the scan never started: its wall-clock budget ran out first. */
|
|
1340
|
+
declare const TAG_SKIPPED_SCAN_BUDGET = "skipped:scan-budget";
|
|
1176
1341
|
/** Display names for the 8 v2 categories. */
|
|
1177
1342
|
declare const CATEGORY_NAMES: Record<string, string>;
|
|
1178
1343
|
declare const READINESS_WEIGHTS: {
|
|
@@ -1200,7 +1365,7 @@ declare function weightForGrade(grade: EvidenceGrade, tier: AuditTier): number;
|
|
|
1200
1365
|
* fails/passes or readiness vitals. Every surface that ranks or scores checks
|
|
1201
1366
|
* filters through this predicate so the rule cannot drift per package.
|
|
1202
1367
|
*/
|
|
1203
|
-
declare function isInformative(check: Pick<CheckResult,
|
|
1368
|
+
declare function isInformative(check: Pick<CheckResult, "scoreDisplayMode">): boolean;
|
|
1204
1369
|
declare function calculateCategoryScore(checks: CheckResult[]): number;
|
|
1205
1370
|
/**
|
|
1206
1371
|
* Assemble a category result.
|
|
@@ -1212,6 +1377,12 @@ declare function calculateCategoryScore(checks: CheckResult[]): number;
|
|
|
1212
1377
|
*/
|
|
1213
1378
|
declare function buildCategoryResult(id: string, checks: CheckResult[], mass?: number): CategoryResult;
|
|
1214
1379
|
declare function calculateOverallScore(categories: CategoryResult[]): number;
|
|
1380
|
+
/**
|
|
1381
|
+
* How much of the registry's evidence mass the checks carrying `tag` hold.
|
|
1382
|
+
* The gate and the scan budget both stub audits as `na` under their own
|
|
1383
|
+
* tag, and each is judged against {@link GATED_MASS_UNSCORED_THRESHOLD}.
|
|
1384
|
+
*/
|
|
1385
|
+
declare function skippedMassShare(checks: CheckResult[], tag: string): number;
|
|
1215
1386
|
|
|
1216
1387
|
/**
|
|
1217
1388
|
* Read product fields straight from the scanned product page(s)' structured
|
|
@@ -1332,6 +1503,7 @@ declare const AuditMetaSchema: z.ZodObject<{
|
|
|
1332
1503
|
description: z.ZodString;
|
|
1333
1504
|
scoreDisplayMode: z.ZodEnum<["binary", "ternary", "informative"]>;
|
|
1334
1505
|
weight: z.ZodNumber;
|
|
1506
|
+
pageTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1335
1507
|
applicablePageTypes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1336
1508
|
defaultPriority: z.ZodEnum<["critical", "high", "medium", "low"]>;
|
|
1337
1509
|
guidance: z.ZodOptional<z.ZodObject<{
|
|
@@ -1382,6 +1554,7 @@ declare const AuditMetaSchema: z.ZodObject<{
|
|
|
1382
1554
|
evidenceGrade: "A" | "B" | "C" | "D";
|
|
1383
1555
|
tier: "informative" | "scored" | "experimental";
|
|
1384
1556
|
dossier: string;
|
|
1557
|
+
pageTypes?: string[] | undefined;
|
|
1385
1558
|
applicablePageTypes?: string[] | undefined;
|
|
1386
1559
|
guidance?: {
|
|
1387
1560
|
impact: string;
|
|
@@ -1408,6 +1581,7 @@ declare const AuditMetaSchema: z.ZodObject<{
|
|
|
1408
1581
|
evidenceGrade: "A" | "B" | "C" | "D";
|
|
1409
1582
|
tier: "informative" | "scored" | "experimental";
|
|
1410
1583
|
dossier: string;
|
|
1584
|
+
pageTypes?: string[] | undefined;
|
|
1411
1585
|
applicablePageTypes?: string[] | undefined;
|
|
1412
1586
|
guidance?: {
|
|
1413
1587
|
impact: string;
|
|
@@ -1526,13 +1700,156 @@ declare const CheckResultSchema: z.ZodObject<{
|
|
|
1526
1700
|
evidenceGrade?: "A" | "B" | "C" | "D" | undefined;
|
|
1527
1701
|
tier?: "informative" | "scored" | "experimental" | undefined;
|
|
1528
1702
|
}>;
|
|
1703
|
+
declare const PageTypeSchema: z.ZodEnum<["homepage", "category", "product", "content"]>;
|
|
1704
|
+
declare const ScanConditionsSchema: z.ZodObject<{
|
|
1705
|
+
url: z.ZodString;
|
|
1706
|
+
pageType: z.ZodObject<{
|
|
1707
|
+
type: z.ZodEnum<["homepage", "category", "product", "content"]>;
|
|
1708
|
+
source: z.ZodEnum<["declared", "detected"]>;
|
|
1709
|
+
}, "strip", z.ZodTypeAny, {
|
|
1710
|
+
type: "homepage" | "category" | "product" | "content";
|
|
1711
|
+
source: "declared" | "detected";
|
|
1712
|
+
}, {
|
|
1713
|
+
type: "homepage" | "category" | "product" | "content";
|
|
1714
|
+
source: "declared" | "detected";
|
|
1715
|
+
}>;
|
|
1716
|
+
origin: z.ZodObject<{
|
|
1717
|
+
origin: z.ZodString;
|
|
1718
|
+
version: z.ZodString;
|
|
1719
|
+
readAt: z.ZodString;
|
|
1720
|
+
cached: z.ZodBoolean;
|
|
1721
|
+
}, "strip", z.ZodTypeAny, {
|
|
1722
|
+
origin: string;
|
|
1723
|
+
version: string;
|
|
1724
|
+
readAt: string;
|
|
1725
|
+
cached: boolean;
|
|
1726
|
+
}, {
|
|
1727
|
+
origin: string;
|
|
1728
|
+
version: string;
|
|
1729
|
+
readAt: string;
|
|
1730
|
+
cached: boolean;
|
|
1731
|
+
}>;
|
|
1732
|
+
coverage: z.ZodObject<{
|
|
1733
|
+
registryMass: z.ZodNumber;
|
|
1734
|
+
assessedMass: z.ZodNumber;
|
|
1735
|
+
pageMass: z.ZodNumber;
|
|
1736
|
+
originMass: z.ZodNumber;
|
|
1737
|
+
gatedMass: z.ZodNumber;
|
|
1738
|
+
}, "strip", z.ZodTypeAny, {
|
|
1739
|
+
registryMass: number;
|
|
1740
|
+
assessedMass: number;
|
|
1741
|
+
pageMass: number;
|
|
1742
|
+
originMass: number;
|
|
1743
|
+
gatedMass: number;
|
|
1744
|
+
}, {
|
|
1745
|
+
registryMass: number;
|
|
1746
|
+
assessedMass: number;
|
|
1747
|
+
pageMass: number;
|
|
1748
|
+
originMass: number;
|
|
1749
|
+
gatedMass: number;
|
|
1750
|
+
}>;
|
|
1751
|
+
unscored: z.ZodObject<{
|
|
1752
|
+
totalCount: z.ZodNumber;
|
|
1753
|
+
informativeCount: z.ZodNumber;
|
|
1754
|
+
gatedCount: z.ZodNumber;
|
|
1755
|
+
reasons: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
1756
|
+
}, "strip", z.ZodTypeAny, {
|
|
1757
|
+
reasons: Record<string, number>;
|
|
1758
|
+
totalCount: number;
|
|
1759
|
+
informativeCount: number;
|
|
1760
|
+
gatedCount: number;
|
|
1761
|
+
}, {
|
|
1762
|
+
reasons: Record<string, number>;
|
|
1763
|
+
totalCount: number;
|
|
1764
|
+
informativeCount: number;
|
|
1765
|
+
gatedCount: number;
|
|
1766
|
+
}>;
|
|
1767
|
+
budget: z.ZodOptional<z.ZodObject<{
|
|
1768
|
+
limitMs: z.ZodNumber;
|
|
1769
|
+
elapsedMs: z.ZodNumber;
|
|
1770
|
+
exhausted: z.ZodBoolean;
|
|
1771
|
+
skippedCount: z.ZodNumber;
|
|
1772
|
+
}, "strip", z.ZodTypeAny, {
|
|
1773
|
+
limitMs: number;
|
|
1774
|
+
elapsedMs: number;
|
|
1775
|
+
exhausted: boolean;
|
|
1776
|
+
skippedCount: number;
|
|
1777
|
+
}, {
|
|
1778
|
+
limitMs: number;
|
|
1779
|
+
elapsedMs: number;
|
|
1780
|
+
exhausted: boolean;
|
|
1781
|
+
skippedCount: number;
|
|
1782
|
+
}>>;
|
|
1783
|
+
}, "strip", z.ZodTypeAny, {
|
|
1784
|
+
url: string;
|
|
1785
|
+
origin: {
|
|
1786
|
+
origin: string;
|
|
1787
|
+
version: string;
|
|
1788
|
+
readAt: string;
|
|
1789
|
+
cached: boolean;
|
|
1790
|
+
};
|
|
1791
|
+
pageType: {
|
|
1792
|
+
type: "homepage" | "category" | "product" | "content";
|
|
1793
|
+
source: "declared" | "detected";
|
|
1794
|
+
};
|
|
1795
|
+
coverage: {
|
|
1796
|
+
registryMass: number;
|
|
1797
|
+
assessedMass: number;
|
|
1798
|
+
pageMass: number;
|
|
1799
|
+
originMass: number;
|
|
1800
|
+
gatedMass: number;
|
|
1801
|
+
};
|
|
1802
|
+
unscored: {
|
|
1803
|
+
reasons: Record<string, number>;
|
|
1804
|
+
totalCount: number;
|
|
1805
|
+
informativeCount: number;
|
|
1806
|
+
gatedCount: number;
|
|
1807
|
+
};
|
|
1808
|
+
budget?: {
|
|
1809
|
+
limitMs: number;
|
|
1810
|
+
elapsedMs: number;
|
|
1811
|
+
exhausted: boolean;
|
|
1812
|
+
skippedCount: number;
|
|
1813
|
+
} | undefined;
|
|
1814
|
+
}, {
|
|
1815
|
+
url: string;
|
|
1816
|
+
origin: {
|
|
1817
|
+
origin: string;
|
|
1818
|
+
version: string;
|
|
1819
|
+
readAt: string;
|
|
1820
|
+
cached: boolean;
|
|
1821
|
+
};
|
|
1822
|
+
pageType: {
|
|
1823
|
+
type: "homepage" | "category" | "product" | "content";
|
|
1824
|
+
source: "declared" | "detected";
|
|
1825
|
+
};
|
|
1826
|
+
coverage: {
|
|
1827
|
+
registryMass: number;
|
|
1828
|
+
assessedMass: number;
|
|
1829
|
+
pageMass: number;
|
|
1830
|
+
originMass: number;
|
|
1831
|
+
gatedMass: number;
|
|
1832
|
+
};
|
|
1833
|
+
unscored: {
|
|
1834
|
+
reasons: Record<string, number>;
|
|
1835
|
+
totalCount: number;
|
|
1836
|
+
informativeCount: number;
|
|
1837
|
+
gatedCount: number;
|
|
1838
|
+
};
|
|
1839
|
+
budget?: {
|
|
1840
|
+
limitMs: number;
|
|
1841
|
+
elapsedMs: number;
|
|
1842
|
+
exhausted: boolean;
|
|
1843
|
+
skippedCount: number;
|
|
1844
|
+
} | undefined;
|
|
1845
|
+
}>;
|
|
1529
1846
|
|
|
1530
1847
|
declare function normalizeUrl(input: string): string;
|
|
1531
1848
|
declare function joinUrl(base: string, path: string): string;
|
|
1532
1849
|
declare function extractDomain(url: string): string;
|
|
1533
1850
|
declare function isPrivateIp(ip: string): boolean;
|
|
1534
1851
|
|
|
1535
|
-
type PresetName =
|
|
1852
|
+
type PresetName = "ecommerce" | "saas" | "content" | "quick" | "full";
|
|
1536
1853
|
interface PresetOptions {
|
|
1537
1854
|
name: PresetName;
|
|
1538
1855
|
description: string;
|
|
@@ -1555,11 +1872,13 @@ interface AgentLighthouseConfig {
|
|
|
1555
1872
|
/** Per-category minimum score assertions */
|
|
1556
1873
|
assertCategories?: Record<string, number>;
|
|
1557
1874
|
/** Output report formats (terminal, html, json, md) */
|
|
1558
|
-
output?: Array<
|
|
1875
|
+
output?: Array<"terminal" | "html" | "json" | "md">;
|
|
1559
1876
|
/** Output directory for reports */
|
|
1560
1877
|
outputDir?: string;
|
|
1561
1878
|
/** Maximum number of pages to discover & scan */
|
|
1562
1879
|
maxPages?: number;
|
|
1880
|
+
/** Scan budget in seconds; 0 disables it. The flag `--timeout` overrides it. */
|
|
1881
|
+
timeout?: number;
|
|
1563
1882
|
}
|
|
1564
1883
|
/** Helper function for type-safe configuration files */
|
|
1565
1884
|
declare function defineConfig(config: AgentLighthouseConfig): AgentLighthouseConfig;
|
|
@@ -1568,7 +1887,7 @@ declare function defineConfig(config: AgentLighthouseConfig): AgentLighthouseCon
|
|
|
1568
1887
|
*/
|
|
1569
1888
|
declare function loadConfigFile(customPath?: string): AgentLighthouseConfig;
|
|
1570
1889
|
|
|
1571
|
-
type LogLevel =
|
|
1890
|
+
type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
1572
1891
|
declare class Logger {
|
|
1573
1892
|
level: LogLevel;
|
|
1574
1893
|
private shouldLog;
|
|
@@ -1590,4 +1909,4 @@ type AcpLinkType = (typeof ACP_LINK_TYPES)[number];
|
|
|
1590
1909
|
*/
|
|
1591
1910
|
declare function resolvePolicyLinks(ctx: CheckContext): Map<AcpLinkType, string>;
|
|
1592
1911
|
|
|
1593
|
-
export { ACP_LINK_TYPES, AI_CRAWLER_UAS, AUDIT_ID_PATTERN, type AcpLinkType, type AgentLighthouseConfig, Audit, type AuditGuidance, AuditGuidanceSchema, type AuditMeta, AuditMetaSchema, type AuditPlan, type AuditProgressEvent, type AuditRegistration, type AuditResult, AuditResultSchema, type AuditRunResult, type AuditTier, AuditTierSchema, type AuditTrace, type AuditTraceHandler, BASELINE_UA, type BlockClass, CATEGORY_IDS, CATEGORY_MASS, CATEGORY_NAMES, type CategoryConfig, type CategoryResult, type CheckContext, type CheckFn, type CheckPriority, CheckPrioritySchema, type CheckRecommendation, type CheckResult, CheckResultSchema, type CheckStatus, CheckStatusSchema, type CssRule, DEFAULT_SCAN_LIMIT, type DeprecationNotice, DeprecationNoticeSchema, type EvidenceGrade, EvidenceGradeSchema, type EvidenceKey, EvidenceKeySchema, type ExpectedKind, type FetchClass, type FetchOptions, type FetchResult, type FetcherOptions, type FieldStatus, type FixEffort, FixEffortSchema, MAX_CONCURRENT_REQUESTS, MAX_PAGES_PER_SCAN, MAX_RESPONSE_BODY_BYTES, PAGE_TYPE_LABELS, PHASE_WEIGHTS, PRESETS, type PageContext, type PageCss, type PageJudgement, type PageOverride, type PageType, type PhaseId, type PresetName, type PresetOptions, type ProductFieldVerification, ProgressTracker, READINESS_WEIGHTS, REQUEST_TIMEOUT_MS, type ReadinessVitals, type RobotsFile, type RobotsGroup, type RobotsRule, SCANNER_USER_AGENT, SCAN_TIMEOUT_MS, SCORE_TIER_LABELS, type ScanConfig, type ScanEvent, type ScanEvidence, type ScanOptions, type ScanReport, type ScanValidity, type ScoreDisplayMode, ScoreDisplayModeSchema, type ScoreTier, type SitemapEntry, type SitemapTree, TAG_SCAN_ERROR, TAG_SKIPPED_NO_EVIDENCE, TAG_SKIPPED_PAGE_TYPE, type UaProbe, type WafProtection, allEvidenceMet, allJsonLdNodes, boundedDispatcher, buildCategoryResult, buildScanEvidence, calculateCategoryScore, calculateOverallScore, classifyFetch, classifyResponse, collectPageCss, collectSitemapEntries, createFetcher, defaultConfig, defineConfig, detectPageType, detectWafProtection, evidenceUrl, extractDomain, extractForms, extractHeadLinks, extractHeadings, extractImages, extractInternalLinks, extractJsonLd, extractMarkdownLinks, extractMetaTags, extractNavLinks, extractProductFieldVerification, extractScripts, extractStylesheetUrls, filterConfig, flattenJsonLd, formatTrace, getMainContentText, getPreset, getRenderedText, getScoreTier, getTierColor, getTierLabel, getWordCount, groupsForBot, hasNamedGroup, isBlanketBlocked, isInformative, isPathAllowed, isPrivateIp, isRealFile, isSafeUrl, isW3CDateTime, joinUrl, judgePages, loadConfigFile, logger, matchesUserAgent, normalizeNewlines, normalizeUrl, outcomeOf, pagesOfType, parseCssRules, parseHtml, parseRobots, parseRobotsFile, planAudits, probeUaParity, resolvePolicyLinks, runAudits, runScan, sampleEntries, stripBom, topLevelJsonLd, traceFromCheck, weightForGrade };
|
|
1912
|
+
export { ACP_LINK_TYPES, AI_CRAWLER_UAS, AUDIT_ID_PATTERN, type AcpLinkType, type AgentLighthouseConfig, Audit, type AuditGuidance, AuditGuidanceSchema, type AuditMeta, AuditMetaSchema, type AuditPlan, type AuditProgressEvent, type AuditRegistration, type AuditResult, AuditResultSchema, type AuditRunResult, type AuditTier, AuditTierSchema, type AuditTrace, type AuditTraceHandler, BASELINE_UA, type BlockClass, CATEGORY_IDS, CATEGORY_MASS, CATEGORY_NAMES, type CategoryConfig, type CategoryResult, type CheckContext, type CheckFn, type CheckPriority, CheckPrioritySchema, type CheckRecommendation, type CheckResult, CheckResultSchema, type CheckStatus, CheckStatusSchema, type CssRule, DEFAULT_ORIGIN_CACHE_MAX_ENTRIES, DEFAULT_ORIGIN_CACHE_TTL_MS, DEFAULT_SCAN_LIMIT, type DeprecationNotice, DeprecationNoticeSchema, type EvidenceGrade, EvidenceGradeSchema, type EvidenceKey, EvidenceKeySchema, type ExpectedKind, type FetchClass, type FetchOptions, type FetchResult, type FetcherOptions, type FieldStatus, type FixEffort, FixEffortSchema, MAX_CONCURRENT_REQUESTS, MAX_PAGES_PER_SCAN, MAX_RESPONSE_BODY_BYTES, ORIGIN_EVIDENCE_VERSION, OriginCache, type OriginCacheOptions, type OriginEvidence, PAGE_TYPE_LABELS, PHASE_WEIGHTS, PRESETS, type PageContext, type PageCss, type PageJudgement, type PageOverride, type PageType, PageTypeSchema, type PhaseId, type PresetName, type PresetOptions, type ProductFieldVerification, ProgressTracker, READINESS_WEIGHTS, REQUEST_TIMEOUT_MS, type ReadinessVitals, type RobotsFile, type RobotsGroup, type RobotsRule, SCANNER_USER_AGENT, SCAN_TIMEOUT_MS, SCORE_TIER_LABELS, type ScanConditions, ScanConditionsSchema, type ScanConfig, type ScanEvent, type ScanEvidence, type ScanOptions, type ScanReport, type ScanValidity, type ScoreDisplayMode, ScoreDisplayModeSchema, type ScoreTier, type SitemapEntry, type SitemapTree, TAG_SCAN_ERROR, TAG_SKIPPED_NO_EVIDENCE, TAG_SKIPPED_PAGE_TYPE, TAG_SKIPPED_SCAN_BUDGET, type UaProbe, type WafProtection, allEvidenceMet, allJsonLdNodes, boundedDispatcher, budgetReason, buildCategoryResult, buildScanEvidence, calculateCategoryScore, calculateOverallScore, classifyFetch, classifyResponse, collectPageCss, collectSitemapEntries, computeOriginCacheKey, createFetcher, defaultConfig, defaultOriginCache, defineConfig, detectPageType, detectWafProtection, evidenceUrl, extractDomain, extractForms, extractHeadLinks, extractHeadings, extractImages, extractInternalLinks, extractJsonLd, extractMarkdownLinks, extractMetaTags, extractNavLinks, extractProductFieldVerification, extractScripts, extractStylesheetUrls, filterConfig, flattenJsonLd, formatBudget, formatTrace, getMainContentText, getPreset, getRenderedText, getScoreTier, getTierColor, getTierLabel, getWordCount, groupsForBot, hasNamedGroup, isBlanketBlocked, isInformative, isPathAllowed, isPrivateIp, isRealFile, isSafeUrl, isW3CDateTime, joinUrl, judgePages, loadConfigFile, logger, matchesUserAgent, normalizeNewlines, normalizeUrl, outcomeOf, pagesOfType, parseCssRules, parseHtml, parseRobots, parseRobotsFile, planAudits, probeUaParity, resolvePolicyLinks, runAudits, runScan, sampleEntries, shouldBypassOriginCache, skippedMassShare, stripBom, topLevelJsonLd, traceFromCheck, weightForGrade };
|