@domandigital/craft 0.11.0 → 0.13.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/CHANGELOG.md +36 -0
- package/CHARACTER.md +100 -1
- package/COPY.md +6 -2
- package/README.md +5 -0
- package/dist/{audit-QIPXL7E4.js → audit-5TYDYRXV.js} +9 -3
- package/dist/audit.cjs +881 -95
- package/dist/audit.d.cts +161 -4
- package/dist/audit.d.ts +161 -4
- package/dist/audit.js +878 -95
- package/dist/{chunk-2AJB27BJ.js → chunk-3VTPI7BU.js} +26 -11
- package/dist/chunk-CZDOMIVS.js +19 -0
- package/dist/chunk-ESCVTKPN.js +217 -0
- package/dist/{chunk-3NGWXZZE.js → chunk-GMVXADJ6.js} +2929 -2082
- package/dist/{chunk-MSQ57PJU.js → chunk-IMB4V34S.js} +31 -18
- package/dist/chunk-JYNXGCYZ.js +75 -0
- package/dist/{chunk-HOHHQB4N.js → chunk-K2BZN4GA.js} +52 -16
- package/dist/{chunk-JP75P2DU.js → chunk-ZLDA2SYB.js} +342 -16
- package/dist/{chunk-JWHC67ZS.js → chunk-ZZ5CKOJP.js} +121 -1
- package/dist/cli-BKJMLD3H.js +18 -0
- package/dist/{cli-U3SZVHSK.js → cli-DRKAMFAH.js} +12 -80
- package/dist/{cli-4ESXOLKV.js → cli-ILH7OO5G.js} +4 -4
- package/dist/{cli-DBZMVYYV.js → cli-J5ECRCD4.js} +17 -17
- package/dist/cli-N2IDXH7W.js +20 -0
- package/dist/cli.js +2 -2
- package/dist/index.cjs +1291 -502
- package/dist/index.d.cts +586 -200
- package/dist/index.d.ts +586 -200
- package/dist/index.js +1263 -502
- package/licences.json +104 -0
- package/package.json +3 -2
- package/word-lists.json +1 -1
- package/dist/chunk-3OZQ4C5R.js +0 -459
- package/dist/chunk-QMYERCBB.js +0 -105
- package/dist/cli-T5RD2BTK.js +0 -17
- package/dist/cli-VREYWCT4.js +0 -16
package/dist/audit.d.cts
CHANGED
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
* to a report and judged again later without a browser. Capturing one needs a
|
|
12
12
|
* browser (see `@domandigital/craft/audit`); judging one does not.
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 2 adds `role` and `geometry` per section, `rhythmVariance` for the page and
|
|
16
|
+
* the screenshot measures in `visual`. All four are optional: a version 1
|
|
17
|
+
* snapshot reads as version 2 without them (see `readSnapshot`), and nothing
|
|
18
|
+
* that judged a v1 snapshot judges it differently.
|
|
19
|
+
*/
|
|
20
|
+
declare const SNAPSHOT_VERSION = 2;
|
|
15
21
|
interface SnapshotColour {
|
|
16
22
|
/** `rgb(r, g, b)` or `rgba(r, g, b, a)`, as the browser computed it. */
|
|
17
23
|
value: string;
|
|
@@ -50,6 +56,27 @@ interface SnapshotControl {
|
|
|
50
56
|
text: string;
|
|
51
57
|
}
|
|
52
58
|
type SectionKind = "hero" | "logos" | "stats" | "cards" | "marquee" | "text" | "other";
|
|
59
|
+
/**
|
|
60
|
+
* What a section is for, finer than `kind`. `kind` keeps its version 1
|
|
61
|
+
* meaning because the rendered tells, the null models and the estate were
|
|
62
|
+
* calibrated on it; `role` is what component-level comparison reads.
|
|
63
|
+
*/
|
|
64
|
+
type SectionRole = SectionKind | "cta-band" | "footer-cta" | "pricing" | "testimonials" | "faq" | "process" | "features" | "team" | "contact";
|
|
65
|
+
/** How a section is laid out, measured, not judged. */
|
|
66
|
+
interface SectionGeometry {
|
|
67
|
+
/** Share of the section's text blocks that are centred, 0 to 1. */
|
|
68
|
+
centredShare: number;
|
|
69
|
+
/** Content area balance about the vertical centre line: 1 mirror-even, 0 all on one side. */
|
|
70
|
+
mirrorSymmetry: number;
|
|
71
|
+
/** Share of the section's area with no text, image or control in it, 0 to 1. */
|
|
72
|
+
whitespaceRatio: number;
|
|
73
|
+
/** Width the content spans, over the viewport width. */
|
|
74
|
+
contentWidthRatio: number;
|
|
75
|
+
/** The painted background behind the section, as computed. */
|
|
76
|
+
background: string;
|
|
77
|
+
/** Buttons and button-styled links in the section. */
|
|
78
|
+
controls: number;
|
|
79
|
+
}
|
|
53
80
|
interface SnapshotSection {
|
|
54
81
|
top: number;
|
|
55
82
|
height: number;
|
|
@@ -62,6 +89,70 @@ interface SnapshotSection {
|
|
|
62
89
|
iconCards: number;
|
|
63
90
|
/** Hidden at load, waiting for a scroll to reveal it. */
|
|
64
91
|
hiddenAtLoad: boolean;
|
|
92
|
+
/** Version 2. */
|
|
93
|
+
role?: SectionRole;
|
|
94
|
+
/** Version 2. */
|
|
95
|
+
geometry?: SectionGeometry;
|
|
96
|
+
/** Version 2: short pill or label texts in the section ("Most popular", "New"), at most 5. */
|
|
97
|
+
badges?: string[];
|
|
98
|
+
/** Version 2: small round portraits (at most 96px, roughly square, radius 40% or more). */
|
|
99
|
+
avatars?: number;
|
|
100
|
+
/** Version 2: a horizontal scroller, snap track or prev/next control holds the content. */
|
|
101
|
+
carousel?: boolean;
|
|
102
|
+
/** Version 2: large standalone figures ("500+", "98%", "4.9/5") at 24px or more. */
|
|
103
|
+
figures?: number;
|
|
104
|
+
}
|
|
105
|
+
type ImageRole = "photo" | "illustration" | "icon" | "avatar" | "logo";
|
|
106
|
+
/**
|
|
107
|
+
* What the image's own bytes say about where it came from. Only a positive
|
|
108
|
+
* is evidence: most images carry no metadata at all, and a re-encode strips
|
|
109
|
+
* it, so no marker proves nothing.
|
|
110
|
+
*/
|
|
111
|
+
interface ImageProvenance {
|
|
112
|
+
/** The IPTC digital source type found, if any: "trainedAlgorithmicMedia" or "compositeWithTrainedAlgorithmicMedia". */
|
|
113
|
+
digitalSourceType: string | null;
|
|
114
|
+
/** Where the marker sat: an XMP packet, a C2PA manifest, or somewhere else in the file. */
|
|
115
|
+
source: "xmp" | "c2pa" | "other" | null;
|
|
116
|
+
/** The file carries a C2PA manifest (Content Credentials), whatever it says. */
|
|
117
|
+
c2pa: boolean;
|
|
118
|
+
/** Bytes read, from the start of the file. */
|
|
119
|
+
bytes: number;
|
|
120
|
+
}
|
|
121
|
+
/** One image as the visitor sees it: an `img`, or a CSS background large enough to be a picture. */
|
|
122
|
+
interface SnapshotImage {
|
|
123
|
+
/** The URL the browser loaded, unwrapped from an image optimiser (`/_next/image?url=`), or a `data:` URI cut to 64 characters. */
|
|
124
|
+
src: string;
|
|
125
|
+
/** Host of `src`, or null for a `data:` URI. */
|
|
126
|
+
host: string | null;
|
|
127
|
+
width: number;
|
|
128
|
+
height: number;
|
|
129
|
+
top: number;
|
|
130
|
+
role: ImageRole;
|
|
131
|
+
alt: string | null;
|
|
132
|
+
/** Empty alt, `aria-hidden` or `role="presentation"`. */
|
|
133
|
+
decorative: boolean;
|
|
134
|
+
/** Index into `sections`, or null when the image sits outside them. */
|
|
135
|
+
section: number | null;
|
|
136
|
+
/** A CSS `background-image`, not an `img`. */
|
|
137
|
+
background: boolean;
|
|
138
|
+
/** Present when the bytes were read. */
|
|
139
|
+
provenance?: ImageProvenance;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Measures of the rendered pixels, from a full-page screenshot (capped at
|
|
143
|
+
* `height`). None of them passes or fails anything: they describe.
|
|
144
|
+
*/
|
|
145
|
+
interface SnapshotVisual {
|
|
146
|
+
/** Hasler and Süsstrunk (2003) colourfulness, M = σ_rgyb + 0.3 μ_rgyb, on 0-255 channels. Grey is 0. */
|
|
147
|
+
colourfulness: number;
|
|
148
|
+
/** Share of sampled pixels on a luminance edge: a complexity proxy, 0 to 1. */
|
|
149
|
+
edgeDensity: number;
|
|
150
|
+
/** 1 minus the mean luminance difference between each pixel and its left-right mirror, 0 to 1. */
|
|
151
|
+
symmetry: number;
|
|
152
|
+
width: number;
|
|
153
|
+
height: number;
|
|
154
|
+
/** Pixels actually read: large pages are sampled on a grid. */
|
|
155
|
+
sampled: number;
|
|
65
156
|
}
|
|
66
157
|
interface SnapshotGradient {
|
|
67
158
|
/** Colour stops, as computed. */
|
|
@@ -116,6 +207,17 @@ interface Snapshot {
|
|
|
116
207
|
sections: SnapshotSection[];
|
|
117
208
|
effects: SnapshotEffects;
|
|
118
209
|
motion: SnapshotMotion;
|
|
210
|
+
/** Version 2: coefficient of variation of the section heights. Null with fewer than two sections. */
|
|
211
|
+
rhythmVariance?: number | null;
|
|
212
|
+
/** Version 2: absent when the page could not be screenshotted. */
|
|
213
|
+
visual?: SnapshotVisual;
|
|
214
|
+
/**
|
|
215
|
+
* Version 2, craft 0.14 and later: every image on the page, largest first, at
|
|
216
|
+
* most 60. Absent in older snapshots, which the imagery tells never judge.
|
|
217
|
+
*/
|
|
218
|
+
images?: SnapshotImage[];
|
|
219
|
+
/** Set when a version 1 snapshot was read and upgraded in memory. */
|
|
220
|
+
migratedFrom?: 1;
|
|
119
221
|
/** The design-system measures trawl has collected since v7, kept so it can switch to this. */
|
|
120
222
|
metrics: {
|
|
121
223
|
fontSizes: number[];
|
|
@@ -266,9 +368,31 @@ type FontClass = "serif" | "sans" | "mono" | "script" | "system";
|
|
|
266
368
|
* Pure. Built from a Snapshot, so it describes what a visitor gets.
|
|
267
369
|
*/
|
|
268
370
|
|
|
269
|
-
|
|
371
|
+
/** One section as layout comparison sees it. */
|
|
372
|
+
interface FingerprintSection {
|
|
373
|
+
role: SectionRole;
|
|
374
|
+
/** Share of centred text, 0 to 1. */
|
|
375
|
+
centred: number;
|
|
376
|
+
/** Content width over viewport width, 0 to 1. */
|
|
377
|
+
width: number;
|
|
378
|
+
/** Left-right balance of the content, 0 to 1. Component comparison only. */
|
|
379
|
+
symmetry?: number;
|
|
380
|
+
/** Buttons in the section. */
|
|
381
|
+
controls?: number;
|
|
382
|
+
/** Cards side by side. */
|
|
383
|
+
cards?: number;
|
|
384
|
+
/** The section's own background, or null when it is the page ground. */
|
|
385
|
+
background?: Oklch | null;
|
|
386
|
+
/** Badge texts ("Most popular"), lower-cased. */
|
|
387
|
+
badges?: string[];
|
|
388
|
+
/** Small round portraits. */
|
|
389
|
+
avatars?: number;
|
|
390
|
+
carousel?: boolean;
|
|
391
|
+
/** Large standalone figures. */
|
|
392
|
+
figures?: number;
|
|
393
|
+
}
|
|
270
394
|
interface Fingerprint {
|
|
271
|
-
version:
|
|
395
|
+
version: 1 | 2;
|
|
272
396
|
/** The most prominent chromatic colour: button fills first, then painted area, then text. */
|
|
273
397
|
accent: Oklch | null;
|
|
274
398
|
ground: Oklch;
|
|
@@ -288,6 +412,8 @@ interface Fingerprint {
|
|
|
288
412
|
effects: string[];
|
|
289
413
|
/** Section kinds in running order, hero first. */
|
|
290
414
|
layout: SectionKind[];
|
|
415
|
+
/** Version 2: present when every section carries a role and geometry. */
|
|
416
|
+
sections?: FingerprintSection[];
|
|
291
417
|
}
|
|
292
418
|
|
|
293
419
|
/**
|
|
@@ -329,6 +455,10 @@ interface SnapshotOptions {
|
|
|
329
455
|
/** A Chromium to launch instead of Playwright's own. Also read from CRAFT_CHROMIUM. */
|
|
330
456
|
executablePath?: string;
|
|
331
457
|
timeoutMs?: number;
|
|
458
|
+
/** Take a screenshot and measure its pixels (`visual`). Default true. */
|
|
459
|
+
visual?: boolean;
|
|
460
|
+
/** Read the first bytes of the page's larger images for AI provenance markers. Default true. */
|
|
461
|
+
provenance?: boolean;
|
|
332
462
|
}
|
|
333
463
|
interface MinimalPage {
|
|
334
464
|
close?(): Promise<void>;
|
|
@@ -338,7 +468,34 @@ interface MinimalPage {
|
|
|
338
468
|
}): Promise<unknown>;
|
|
339
469
|
evaluate<R>(fn: () => R): Promise<R>;
|
|
340
470
|
waitForTimeout(ms: number): Promise<void>;
|
|
471
|
+
/** Optional: a driver without it gets a snapshot with no `visual` measures. */
|
|
472
|
+
screenshot?(options: {
|
|
473
|
+
fullPage?: boolean;
|
|
474
|
+
type?: "png";
|
|
475
|
+
clip?: {
|
|
476
|
+
x: number;
|
|
477
|
+
y: number;
|
|
478
|
+
width: number;
|
|
479
|
+
height: number;
|
|
480
|
+
};
|
|
481
|
+
}): Promise<Uint8Array>;
|
|
482
|
+
/** Optional: Playwright's request context, which fetches outside the page's CORS rules. Without it, no image gets `provenance`. */
|
|
483
|
+
request?: {
|
|
484
|
+
get(url: string, options?: {
|
|
485
|
+
headers?: Record<string, string>;
|
|
486
|
+
timeout?: number;
|
|
487
|
+
}): Promise<{
|
|
488
|
+
ok(): boolean;
|
|
489
|
+
body(): Promise<Uint8Array>;
|
|
490
|
+
}>;
|
|
491
|
+
};
|
|
341
492
|
}
|
|
493
|
+
/** At most this many images are read for provenance, largest first. */
|
|
494
|
+
declare const PROVENANCE_MAX_IMAGES = 24;
|
|
495
|
+
/** The most time the reads may take for one page, in ms, so a machine offline waits seconds, not minutes. */
|
|
496
|
+
declare const PROVENANCE_BUDGET_MS = 20000;
|
|
497
|
+
/** The most of a page the screenshot measures read, in CSS px. A long page is judged on its opening. */
|
|
498
|
+
declare const VISUAL_MAX_HEIGHT = 6000;
|
|
342
499
|
interface MinimalBrowser {
|
|
343
500
|
newPage(options?: {
|
|
344
501
|
viewport?: {
|
|
@@ -388,4 +545,4 @@ interface AuditResult {
|
|
|
388
545
|
/** Snapshot a URL, judge it against the rendered tells, and fingerprint it. */
|
|
389
546
|
declare function audit(url: string, options?: SnapshotOptions & CheckOptions): Promise<AuditResult>;
|
|
390
547
|
|
|
391
|
-
export { type AuditResult, type SnapshotOptions, type SnapshotResult, audit, collectInPage, loadPlaywright, overlayInPage, snapshotPage, snapshotUrl, snapshotUrls };
|
|
548
|
+
export { type AuditResult, PROVENANCE_BUDGET_MS, PROVENANCE_MAX_IMAGES, type SnapshotOptions, type SnapshotResult, VISUAL_MAX_HEIGHT, audit, collectInPage, loadPlaywright, overlayInPage, snapshotPage, snapshotUrl, snapshotUrls };
|
package/dist/audit.d.ts
CHANGED
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
* to a report and judged again later without a browser. Capturing one needs a
|
|
12
12
|
* browser (see `@domandigital/craft/audit`); judging one does not.
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 2 adds `role` and `geometry` per section, `rhythmVariance` for the page and
|
|
16
|
+
* the screenshot measures in `visual`. All four are optional: a version 1
|
|
17
|
+
* snapshot reads as version 2 without them (see `readSnapshot`), and nothing
|
|
18
|
+
* that judged a v1 snapshot judges it differently.
|
|
19
|
+
*/
|
|
20
|
+
declare const SNAPSHOT_VERSION = 2;
|
|
15
21
|
interface SnapshotColour {
|
|
16
22
|
/** `rgb(r, g, b)` or `rgba(r, g, b, a)`, as the browser computed it. */
|
|
17
23
|
value: string;
|
|
@@ -50,6 +56,27 @@ interface SnapshotControl {
|
|
|
50
56
|
text: string;
|
|
51
57
|
}
|
|
52
58
|
type SectionKind = "hero" | "logos" | "stats" | "cards" | "marquee" | "text" | "other";
|
|
59
|
+
/**
|
|
60
|
+
* What a section is for, finer than `kind`. `kind` keeps its version 1
|
|
61
|
+
* meaning because the rendered tells, the null models and the estate were
|
|
62
|
+
* calibrated on it; `role` is what component-level comparison reads.
|
|
63
|
+
*/
|
|
64
|
+
type SectionRole = SectionKind | "cta-band" | "footer-cta" | "pricing" | "testimonials" | "faq" | "process" | "features" | "team" | "contact";
|
|
65
|
+
/** How a section is laid out, measured, not judged. */
|
|
66
|
+
interface SectionGeometry {
|
|
67
|
+
/** Share of the section's text blocks that are centred, 0 to 1. */
|
|
68
|
+
centredShare: number;
|
|
69
|
+
/** Content area balance about the vertical centre line: 1 mirror-even, 0 all on one side. */
|
|
70
|
+
mirrorSymmetry: number;
|
|
71
|
+
/** Share of the section's area with no text, image or control in it, 0 to 1. */
|
|
72
|
+
whitespaceRatio: number;
|
|
73
|
+
/** Width the content spans, over the viewport width. */
|
|
74
|
+
contentWidthRatio: number;
|
|
75
|
+
/** The painted background behind the section, as computed. */
|
|
76
|
+
background: string;
|
|
77
|
+
/** Buttons and button-styled links in the section. */
|
|
78
|
+
controls: number;
|
|
79
|
+
}
|
|
53
80
|
interface SnapshotSection {
|
|
54
81
|
top: number;
|
|
55
82
|
height: number;
|
|
@@ -62,6 +89,70 @@ interface SnapshotSection {
|
|
|
62
89
|
iconCards: number;
|
|
63
90
|
/** Hidden at load, waiting for a scroll to reveal it. */
|
|
64
91
|
hiddenAtLoad: boolean;
|
|
92
|
+
/** Version 2. */
|
|
93
|
+
role?: SectionRole;
|
|
94
|
+
/** Version 2. */
|
|
95
|
+
geometry?: SectionGeometry;
|
|
96
|
+
/** Version 2: short pill or label texts in the section ("Most popular", "New"), at most 5. */
|
|
97
|
+
badges?: string[];
|
|
98
|
+
/** Version 2: small round portraits (at most 96px, roughly square, radius 40% or more). */
|
|
99
|
+
avatars?: number;
|
|
100
|
+
/** Version 2: a horizontal scroller, snap track or prev/next control holds the content. */
|
|
101
|
+
carousel?: boolean;
|
|
102
|
+
/** Version 2: large standalone figures ("500+", "98%", "4.9/5") at 24px or more. */
|
|
103
|
+
figures?: number;
|
|
104
|
+
}
|
|
105
|
+
type ImageRole = "photo" | "illustration" | "icon" | "avatar" | "logo";
|
|
106
|
+
/**
|
|
107
|
+
* What the image's own bytes say about where it came from. Only a positive
|
|
108
|
+
* is evidence: most images carry no metadata at all, and a re-encode strips
|
|
109
|
+
* it, so no marker proves nothing.
|
|
110
|
+
*/
|
|
111
|
+
interface ImageProvenance {
|
|
112
|
+
/** The IPTC digital source type found, if any: "trainedAlgorithmicMedia" or "compositeWithTrainedAlgorithmicMedia". */
|
|
113
|
+
digitalSourceType: string | null;
|
|
114
|
+
/** Where the marker sat: an XMP packet, a C2PA manifest, or somewhere else in the file. */
|
|
115
|
+
source: "xmp" | "c2pa" | "other" | null;
|
|
116
|
+
/** The file carries a C2PA manifest (Content Credentials), whatever it says. */
|
|
117
|
+
c2pa: boolean;
|
|
118
|
+
/** Bytes read, from the start of the file. */
|
|
119
|
+
bytes: number;
|
|
120
|
+
}
|
|
121
|
+
/** One image as the visitor sees it: an `img`, or a CSS background large enough to be a picture. */
|
|
122
|
+
interface SnapshotImage {
|
|
123
|
+
/** The URL the browser loaded, unwrapped from an image optimiser (`/_next/image?url=`), or a `data:` URI cut to 64 characters. */
|
|
124
|
+
src: string;
|
|
125
|
+
/** Host of `src`, or null for a `data:` URI. */
|
|
126
|
+
host: string | null;
|
|
127
|
+
width: number;
|
|
128
|
+
height: number;
|
|
129
|
+
top: number;
|
|
130
|
+
role: ImageRole;
|
|
131
|
+
alt: string | null;
|
|
132
|
+
/** Empty alt, `aria-hidden` or `role="presentation"`. */
|
|
133
|
+
decorative: boolean;
|
|
134
|
+
/** Index into `sections`, or null when the image sits outside them. */
|
|
135
|
+
section: number | null;
|
|
136
|
+
/** A CSS `background-image`, not an `img`. */
|
|
137
|
+
background: boolean;
|
|
138
|
+
/** Present when the bytes were read. */
|
|
139
|
+
provenance?: ImageProvenance;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Measures of the rendered pixels, from a full-page screenshot (capped at
|
|
143
|
+
* `height`). None of them passes or fails anything: they describe.
|
|
144
|
+
*/
|
|
145
|
+
interface SnapshotVisual {
|
|
146
|
+
/** Hasler and Süsstrunk (2003) colourfulness, M = σ_rgyb + 0.3 μ_rgyb, on 0-255 channels. Grey is 0. */
|
|
147
|
+
colourfulness: number;
|
|
148
|
+
/** Share of sampled pixels on a luminance edge: a complexity proxy, 0 to 1. */
|
|
149
|
+
edgeDensity: number;
|
|
150
|
+
/** 1 minus the mean luminance difference between each pixel and its left-right mirror, 0 to 1. */
|
|
151
|
+
symmetry: number;
|
|
152
|
+
width: number;
|
|
153
|
+
height: number;
|
|
154
|
+
/** Pixels actually read: large pages are sampled on a grid. */
|
|
155
|
+
sampled: number;
|
|
65
156
|
}
|
|
66
157
|
interface SnapshotGradient {
|
|
67
158
|
/** Colour stops, as computed. */
|
|
@@ -116,6 +207,17 @@ interface Snapshot {
|
|
|
116
207
|
sections: SnapshotSection[];
|
|
117
208
|
effects: SnapshotEffects;
|
|
118
209
|
motion: SnapshotMotion;
|
|
210
|
+
/** Version 2: coefficient of variation of the section heights. Null with fewer than two sections. */
|
|
211
|
+
rhythmVariance?: number | null;
|
|
212
|
+
/** Version 2: absent when the page could not be screenshotted. */
|
|
213
|
+
visual?: SnapshotVisual;
|
|
214
|
+
/**
|
|
215
|
+
* Version 2, craft 0.14 and later: every image on the page, largest first, at
|
|
216
|
+
* most 60. Absent in older snapshots, which the imagery tells never judge.
|
|
217
|
+
*/
|
|
218
|
+
images?: SnapshotImage[];
|
|
219
|
+
/** Set when a version 1 snapshot was read and upgraded in memory. */
|
|
220
|
+
migratedFrom?: 1;
|
|
119
221
|
/** The design-system measures trawl has collected since v7, kept so it can switch to this. */
|
|
120
222
|
metrics: {
|
|
121
223
|
fontSizes: number[];
|
|
@@ -266,9 +368,31 @@ type FontClass = "serif" | "sans" | "mono" | "script" | "system";
|
|
|
266
368
|
* Pure. Built from a Snapshot, so it describes what a visitor gets.
|
|
267
369
|
*/
|
|
268
370
|
|
|
269
|
-
|
|
371
|
+
/** One section as layout comparison sees it. */
|
|
372
|
+
interface FingerprintSection {
|
|
373
|
+
role: SectionRole;
|
|
374
|
+
/** Share of centred text, 0 to 1. */
|
|
375
|
+
centred: number;
|
|
376
|
+
/** Content width over viewport width, 0 to 1. */
|
|
377
|
+
width: number;
|
|
378
|
+
/** Left-right balance of the content, 0 to 1. Component comparison only. */
|
|
379
|
+
symmetry?: number;
|
|
380
|
+
/** Buttons in the section. */
|
|
381
|
+
controls?: number;
|
|
382
|
+
/** Cards side by side. */
|
|
383
|
+
cards?: number;
|
|
384
|
+
/** The section's own background, or null when it is the page ground. */
|
|
385
|
+
background?: Oklch | null;
|
|
386
|
+
/** Badge texts ("Most popular"), lower-cased. */
|
|
387
|
+
badges?: string[];
|
|
388
|
+
/** Small round portraits. */
|
|
389
|
+
avatars?: number;
|
|
390
|
+
carousel?: boolean;
|
|
391
|
+
/** Large standalone figures. */
|
|
392
|
+
figures?: number;
|
|
393
|
+
}
|
|
270
394
|
interface Fingerprint {
|
|
271
|
-
version:
|
|
395
|
+
version: 1 | 2;
|
|
272
396
|
/** The most prominent chromatic colour: button fills first, then painted area, then text. */
|
|
273
397
|
accent: Oklch | null;
|
|
274
398
|
ground: Oklch;
|
|
@@ -288,6 +412,8 @@ interface Fingerprint {
|
|
|
288
412
|
effects: string[];
|
|
289
413
|
/** Section kinds in running order, hero first. */
|
|
290
414
|
layout: SectionKind[];
|
|
415
|
+
/** Version 2: present when every section carries a role and geometry. */
|
|
416
|
+
sections?: FingerprintSection[];
|
|
291
417
|
}
|
|
292
418
|
|
|
293
419
|
/**
|
|
@@ -329,6 +455,10 @@ interface SnapshotOptions {
|
|
|
329
455
|
/** A Chromium to launch instead of Playwright's own. Also read from CRAFT_CHROMIUM. */
|
|
330
456
|
executablePath?: string;
|
|
331
457
|
timeoutMs?: number;
|
|
458
|
+
/** Take a screenshot and measure its pixels (`visual`). Default true. */
|
|
459
|
+
visual?: boolean;
|
|
460
|
+
/** Read the first bytes of the page's larger images for AI provenance markers. Default true. */
|
|
461
|
+
provenance?: boolean;
|
|
332
462
|
}
|
|
333
463
|
interface MinimalPage {
|
|
334
464
|
close?(): Promise<void>;
|
|
@@ -338,7 +468,34 @@ interface MinimalPage {
|
|
|
338
468
|
}): Promise<unknown>;
|
|
339
469
|
evaluate<R>(fn: () => R): Promise<R>;
|
|
340
470
|
waitForTimeout(ms: number): Promise<void>;
|
|
471
|
+
/** Optional: a driver without it gets a snapshot with no `visual` measures. */
|
|
472
|
+
screenshot?(options: {
|
|
473
|
+
fullPage?: boolean;
|
|
474
|
+
type?: "png";
|
|
475
|
+
clip?: {
|
|
476
|
+
x: number;
|
|
477
|
+
y: number;
|
|
478
|
+
width: number;
|
|
479
|
+
height: number;
|
|
480
|
+
};
|
|
481
|
+
}): Promise<Uint8Array>;
|
|
482
|
+
/** Optional: Playwright's request context, which fetches outside the page's CORS rules. Without it, no image gets `provenance`. */
|
|
483
|
+
request?: {
|
|
484
|
+
get(url: string, options?: {
|
|
485
|
+
headers?: Record<string, string>;
|
|
486
|
+
timeout?: number;
|
|
487
|
+
}): Promise<{
|
|
488
|
+
ok(): boolean;
|
|
489
|
+
body(): Promise<Uint8Array>;
|
|
490
|
+
}>;
|
|
491
|
+
};
|
|
341
492
|
}
|
|
493
|
+
/** At most this many images are read for provenance, largest first. */
|
|
494
|
+
declare const PROVENANCE_MAX_IMAGES = 24;
|
|
495
|
+
/** The most time the reads may take for one page, in ms, so a machine offline waits seconds, not minutes. */
|
|
496
|
+
declare const PROVENANCE_BUDGET_MS = 20000;
|
|
497
|
+
/** The most of a page the screenshot measures read, in CSS px. A long page is judged on its opening. */
|
|
498
|
+
declare const VISUAL_MAX_HEIGHT = 6000;
|
|
342
499
|
interface MinimalBrowser {
|
|
343
500
|
newPage(options?: {
|
|
344
501
|
viewport?: {
|
|
@@ -388,4 +545,4 @@ interface AuditResult {
|
|
|
388
545
|
/** Snapshot a URL, judge it against the rendered tells, and fingerprint it. */
|
|
389
546
|
declare function audit(url: string, options?: SnapshotOptions & CheckOptions): Promise<AuditResult>;
|
|
390
547
|
|
|
391
|
-
export { type AuditResult, type SnapshotOptions, type SnapshotResult, audit, collectInPage, loadPlaywright, overlayInPage, snapshotPage, snapshotUrl, snapshotUrls };
|
|
548
|
+
export { type AuditResult, PROVENANCE_BUDGET_MS, PROVENANCE_MAX_IMAGES, type SnapshotOptions, type SnapshotResult, VISUAL_MAX_HEIGHT, audit, collectInPage, loadPlaywright, overlayInPage, snapshotPage, snapshotUrl, snapshotUrls };
|