@juangadm/pre-post 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -20
- package/dist/baseline.d.ts +208 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +413 -0
- package/dist/baseline.js.map +1 -0
- package/dist/bin/cli.js +87 -42
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser.d.ts +31 -3
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +291 -97
- package/dist/browser.js.map +1 -1
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +21 -3
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/detect.d.ts +5 -0
- package/dist/commands/detect.d.ts.map +1 -1
- package/dist/commands/detect.js +4 -1
- package/dist/commands/detect.js.map +1 -1
- package/dist/commands/doctor.d.ts +32 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +90 -9
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/pr.d.ts +4 -0
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +157 -51
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/prune.js +1 -1
- package/dist/commands/prune.js.map +1 -1
- package/dist/comparison.d.ts +104 -0
- package/dist/comparison.d.ts.map +1 -0
- package/dist/comparison.js +241 -0
- package/dist/comparison.js.map +1 -0
- package/dist/config.d.ts +12 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -3
- package/dist/config.js.map +1 -1
- package/dist/deployments.d.ts +71 -0
- package/dist/deployments.d.ts.map +1 -0
- package/dist/deployments.js +204 -0
- package/dist/deployments.js.map +1 -0
- package/dist/diff-pool.d.ts.map +1 -1
- package/dist/diff-pool.js +5 -2
- package/dist/diff-pool.js.map +1 -1
- package/dist/diff-worker.d.ts +3 -0
- package/dist/diff-worker.d.ts.map +1 -1
- package/dist/diff-worker.js +1 -0
- package/dist/diff-worker.js.map +1 -1
- package/dist/diff.d.ts +10 -0
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +117 -7
- package/dist/diff.js.map +1 -1
- package/dist/doctor.d.ts +42 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +73 -7
- package/dist/doctor.js.map +1 -1
- package/dist/git.d.ts +41 -3
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +103 -7
- package/dist/git.js.map +1 -1
- package/dist/github.d.ts +92 -2
- package/dist/github.d.ts.map +1 -1
- package/dist/github.js +191 -20
- package/dist/github.js.map +1 -1
- package/dist/landing.d.ts +48 -0
- package/dist/landing.d.ts.map +1 -0
- package/dist/landing.js +93 -0
- package/dist/landing.js.map +1 -0
- package/dist/pkg.d.ts +9 -0
- package/dist/pkg.d.ts.map +1 -1
- package/dist/pkg.js +14 -0
- package/dist/pkg.js.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +59 -28
- package/dist/report.js.map +1 -1
- package/dist/routes.d.ts +27 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +98 -23
- package/dist/routes.js.map +1 -1
- package/dist/run.d.ts +88 -8
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +224 -28
- package/dist/run.js.map +1 -1
- package/dist/sameness.d.ts +91 -0
- package/dist/sameness.d.ts.map +1 -0
- package/dist/sameness.js +157 -0
- package/dist/sameness.js.map +1 -0
- package/dist/sessions.d.ts.map +1 -1
- package/dist/sessions.js +7 -1
- package/dist/sessions.js.map +1 -1
- package/dist/shift.d.ts +67 -0
- package/dist/shift.d.ts.map +1 -0
- package/dist/shift.js +184 -0
- package/dist/shift.js.map +1 -0
- package/dist/types.d.ts +83 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -1
- package/dist/url.d.ts +12 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +30 -0
- package/dist/url.js.map +1 -0
- package/package.json +1 -1
- package/skill/SKILL.md +40 -7
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Are the two sides the same site at all?
|
|
3
|
+
*
|
|
4
|
+
* The backstop this file exists to be was first specified as "a diff near 100%
|
|
5
|
+
* on every route means the two sides are different sites". Measured, that rule
|
|
6
|
+
* is wrong in both directions, and it is worth writing down why so it is not
|
|
7
|
+
* proposed again:
|
|
8
|
+
*
|
|
9
|
+
* | pair | changed |
|
|
10
|
+
* |-------------------------------------------------|---------|
|
|
11
|
+
* | the marketing site vs an unrelated real site | 2.66% desktop / 5.02% mobile |
|
|
12
|
+
* | fixture pricing page vs an unrelated fixture | 0.72% – 7.99% |
|
|
13
|
+
* | the same site with a full theme change (fixture) | 99.14% |
|
|
14
|
+
* | the same site redesigned (fixture rung-7) | 99.60% |
|
|
15
|
+
*
|
|
16
|
+
* Web pages are mostly background, and a pixel diff counts pixels that differ,
|
|
17
|
+
* so two *unrelated* pages agree on most of the canvas and read as a small
|
|
18
|
+
* change — the same 1-8% band as the login-page run that started all of this
|
|
19
|
+
* (4.53% / 1.99%). Meanwhile a legitimate redesign, the PR most worth
|
|
20
|
+
* screenshotting, reads ~100%. A threshold at 100% would have missed every
|
|
21
|
+
* real occurrence and fired on the best ones.
|
|
22
|
+
*
|
|
23
|
+
* What does separate them is the words on the page. A redesign changes how a
|
|
24
|
+
* page looks, not what it says; a different site says something else entirely.
|
|
25
|
+
* Measured over the same pairs, with common English words removed:
|
|
26
|
+
*
|
|
27
|
+
* different sites 0.000, 0.000, 0.000, 0.071
|
|
28
|
+
* same site 0.200 (the weakest fixture), 0.417+, 1.000 for real pages
|
|
29
|
+
*
|
|
30
|
+
* The floor below sits in that empty band.
|
|
31
|
+
*/
|
|
32
|
+
/** The distinctive words a page shows a reader. */
|
|
33
|
+
export declare function pageWords(text: string): Set<string>;
|
|
34
|
+
/**
|
|
35
|
+
* A page with almost nothing to say cannot answer this question: an image or a
|
|
36
|
+
* canvas with six words on it scores near zero against anything, including
|
|
37
|
+
* itself one version later. Below this many distinct words, the answer is "do
|
|
38
|
+
* not know" rather than "different".
|
|
39
|
+
*/
|
|
40
|
+
export declare const MIN_WORDS = 10;
|
|
41
|
+
/** The floor, from the measurements above: 0.071 was different, 0.200 was not. */
|
|
42
|
+
export declare const SAME_SITE_FLOOR = 0.1;
|
|
43
|
+
/** Overlap of two pages' body text, or null when either is too text-poor to judge. */
|
|
44
|
+
export declare function textOverlap(before: string, after: string): number | null;
|
|
45
|
+
/**
|
|
46
|
+
* Overlap of two pages' titles, or null when either says nothing distinctive.
|
|
47
|
+
*
|
|
48
|
+
* No `MIN_WORDS` here: a title is a handful of words by nature, and it is the
|
|
49
|
+
* one place a site almost always names itself. That makes it the corroborating
|
|
50
|
+
* signal for a run with only one route to go on — a branch that rewrites a
|
|
51
|
+
* page's copy keeps the site's name in the tab, a different site does not.
|
|
52
|
+
*/
|
|
53
|
+
export declare function titleOverlap(before: string, after: string): number | null;
|
|
54
|
+
/** What this needs from each capture: which page it was, and how the two sides compared. */
|
|
55
|
+
export interface RouteEvidence {
|
|
56
|
+
route?: string;
|
|
57
|
+
textOverlap?: number | null;
|
|
58
|
+
titleOverlap?: number | null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Do the captures, taken together, say these are two different sites?
|
|
62
|
+
*
|
|
63
|
+
* Every judgeable page has to disagree, and the evidence has to be about
|
|
64
|
+
* *pages*, not captures. One route shot at three viewports is one page's word
|
|
65
|
+
* list three times over; counting it as three agreeing witnesses is how a run
|
|
66
|
+
* that detected a single route — an explicit `--routes /`, or the `/` fallback
|
|
67
|
+
* when the diff names none — could reject the one thing this function's own
|
|
68
|
+
* rule permits: a branch that rewrote a page.
|
|
69
|
+
*
|
|
70
|
+
* So captures are folded per route, keeping each route's *strongest* showing of
|
|
71
|
+
* shared words, and a run with only one page to go on asks the title as well. A
|
|
72
|
+
* title is where a site names itself, so a rewritten page keeps it and a
|
|
73
|
+
* different site does not. Without a usable title there is no second witness
|
|
74
|
+
* and the run is published, which is the right way to be wrong here: publishing
|
|
75
|
+
* a diff someone can look at beats refusing to on one page's say-so.
|
|
76
|
+
*/
|
|
77
|
+
export declare function looksLikeDifferentSites(routes: RouteEvidence[]): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* The one sentence a human needs when the two sides are not the same site.
|
|
80
|
+
*
|
|
81
|
+
* `beforeDetail` is how Pre was chosen ("production deployment for 26aa6cd"),
|
|
82
|
+
* absent when a caller was handed both URLs by hand and has no provenance to
|
|
83
|
+
* report. `fix` is the remedy, which is the caller's to name: telling someone
|
|
84
|
+
* to pass `--before` is right when the tool picked the baseline and wrong in
|
|
85
|
+
* the two-URL mode, where both sides came in as positional arguments and that
|
|
86
|
+
* flag is not how the command is invoked. Advice that does not apply to the
|
|
87
|
+
* mode you are in is the failure this project keeps finding — it is what sent
|
|
88
|
+
* someone to sign in to a macOS system service.
|
|
89
|
+
*/
|
|
90
|
+
export declare function differentSitesHint(beforeUrl: string, beforeDetail: string | undefined, afterUrl: string, fix?: string): string;
|
|
91
|
+
//# sourceMappingURL=sameness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sameness.d.ts","sourceRoot":"","sources":["../src/sameness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAeH,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAGnD;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B,kFAAkF;AAClF,eAAO,MAAM,eAAe,MAAM,CAAC;AAgBnC,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKxE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKzE;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAkBxE;AAYD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAoC,GACxC,MAAM,CAGR"}
|
package/dist/sameness.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Are the two sides the same site at all?
|
|
3
|
+
*
|
|
4
|
+
* The backstop this file exists to be was first specified as "a diff near 100%
|
|
5
|
+
* on every route means the two sides are different sites". Measured, that rule
|
|
6
|
+
* is wrong in both directions, and it is worth writing down why so it is not
|
|
7
|
+
* proposed again:
|
|
8
|
+
*
|
|
9
|
+
* | pair | changed |
|
|
10
|
+
* |-------------------------------------------------|---------|
|
|
11
|
+
* | the marketing site vs an unrelated real site | 2.66% desktop / 5.02% mobile |
|
|
12
|
+
* | fixture pricing page vs an unrelated fixture | 0.72% – 7.99% |
|
|
13
|
+
* | the same site with a full theme change (fixture) | 99.14% |
|
|
14
|
+
* | the same site redesigned (fixture rung-7) | 99.60% |
|
|
15
|
+
*
|
|
16
|
+
* Web pages are mostly background, and a pixel diff counts pixels that differ,
|
|
17
|
+
* so two *unrelated* pages agree on most of the canvas and read as a small
|
|
18
|
+
* change — the same 1-8% band as the login-page run that started all of this
|
|
19
|
+
* (4.53% / 1.99%). Meanwhile a legitimate redesign, the PR most worth
|
|
20
|
+
* screenshotting, reads ~100%. A threshold at 100% would have missed every
|
|
21
|
+
* real occurrence and fired on the best ones.
|
|
22
|
+
*
|
|
23
|
+
* What does separate them is the words on the page. A redesign changes how a
|
|
24
|
+
* page looks, not what it says; a different site says something else entirely.
|
|
25
|
+
* Measured over the same pairs, with common English words removed:
|
|
26
|
+
*
|
|
27
|
+
* different sites 0.000, 0.000, 0.000, 0.071
|
|
28
|
+
* same site 0.200 (the weakest fixture), 0.417+, 1.000 for real pages
|
|
29
|
+
*
|
|
30
|
+
* The floor below sits in that empty band.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Words too common to say anything about which site you are on. Without this,
|
|
34
|
+
* two unrelated English pages score 0.18 on shared articles and prepositions
|
|
35
|
+
* alone, which is close enough to the weakest same-site pair (0.20) to make the
|
|
36
|
+
* test unusable.
|
|
37
|
+
*/
|
|
38
|
+
const STOP_WORDS = new Set(('the and for you your are with that this from all not our but can has have was were will more than then ' +
|
|
39
|
+
'when who how why into out off over under new get set use using its about here there they them their ' +
|
|
40
|
+
'his her she him one two any some each own too very just also only same such per via yes non')
|
|
41
|
+
.split(' '));
|
|
42
|
+
/** The distinctive words a page shows a reader. */
|
|
43
|
+
export function pageWords(text) {
|
|
44
|
+
const found = text.toLowerCase().match(/[a-z0-9']{3,}/g) ?? [];
|
|
45
|
+
return new Set(found.filter(w => !STOP_WORDS.has(w)));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A page with almost nothing to say cannot answer this question: an image or a
|
|
49
|
+
* canvas with six words on it scores near zero against anything, including
|
|
50
|
+
* itself one version later. Below this many distinct words, the answer is "do
|
|
51
|
+
* not know" rather than "different".
|
|
52
|
+
*/
|
|
53
|
+
export const MIN_WORDS = 10;
|
|
54
|
+
/** The floor, from the measurements above: 0.071 was different, 0.200 was not. */
|
|
55
|
+
export const SAME_SITE_FLOOR = 0.1;
|
|
56
|
+
/**
|
|
57
|
+
* How much of the smaller vocabulary the larger one also has.
|
|
58
|
+
*
|
|
59
|
+
* Containment rather than Jaccard because the two sides legitimately differ in
|
|
60
|
+
* length — a branch that adds a section should not read as a different site for
|
|
61
|
+
* having more words than the baseline.
|
|
62
|
+
*/
|
|
63
|
+
function containment(a, b) {
|
|
64
|
+
const [small, large] = a.size <= b.size ? [a, b] : [b, a];
|
|
65
|
+
let shared = 0;
|
|
66
|
+
for (const word of small)
|
|
67
|
+
if (large.has(word))
|
|
68
|
+
shared++;
|
|
69
|
+
return shared / small.size;
|
|
70
|
+
}
|
|
71
|
+
/** Overlap of two pages' body text, or null when either is too text-poor to judge. */
|
|
72
|
+
export function textOverlap(before, after) {
|
|
73
|
+
const a = pageWords(before);
|
|
74
|
+
const b = pageWords(after);
|
|
75
|
+
if (a.size < MIN_WORDS || b.size < MIN_WORDS)
|
|
76
|
+
return null;
|
|
77
|
+
return containment(a, b);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Overlap of two pages' titles, or null when either says nothing distinctive.
|
|
81
|
+
*
|
|
82
|
+
* No `MIN_WORDS` here: a title is a handful of words by nature, and it is the
|
|
83
|
+
* one place a site almost always names itself. That makes it the corroborating
|
|
84
|
+
* signal for a run with only one route to go on — a branch that rewrites a
|
|
85
|
+
* page's copy keeps the site's name in the tab, a different site does not.
|
|
86
|
+
*/
|
|
87
|
+
export function titleOverlap(before, after) {
|
|
88
|
+
const a = pageWords(before);
|
|
89
|
+
const b = pageWords(after);
|
|
90
|
+
if (!a.size || !b.size)
|
|
91
|
+
return null;
|
|
92
|
+
return containment(a, b);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Do the captures, taken together, say these are two different sites?
|
|
96
|
+
*
|
|
97
|
+
* Every judgeable page has to disagree, and the evidence has to be about
|
|
98
|
+
* *pages*, not captures. One route shot at three viewports is one page's word
|
|
99
|
+
* list three times over; counting it as three agreeing witnesses is how a run
|
|
100
|
+
* that detected a single route — an explicit `--routes /`, or the `/` fallback
|
|
101
|
+
* when the diff names none — could reject the one thing this function's own
|
|
102
|
+
* rule permits: a branch that rewrote a page.
|
|
103
|
+
*
|
|
104
|
+
* So captures are folded per route, keeping each route's *strongest* showing of
|
|
105
|
+
* shared words, and a run with only one page to go on asks the title as well. A
|
|
106
|
+
* title is where a site names itself, so a rewritten page keeps it and a
|
|
107
|
+
* different site does not. Without a usable title there is no second witness
|
|
108
|
+
* and the run is published, which is the right way to be wrong here: publishing
|
|
109
|
+
* a diff someone can look at beats refusing to on one page's say-so.
|
|
110
|
+
*/
|
|
111
|
+
export function looksLikeDifferentSites(routes) {
|
|
112
|
+
const pages = new Map();
|
|
113
|
+
for (const [i, r] of routes.entries()) {
|
|
114
|
+
const key = r.route ?? `#${i}`;
|
|
115
|
+
const seen = pages.get(key);
|
|
116
|
+
// The best showing across viewports: any viewport that found shared words
|
|
117
|
+
// clears the page, so a single narrow layout cannot condemn it alone.
|
|
118
|
+
pages.set(key, {
|
|
119
|
+
text: strongest(seen?.text, r.textOverlap),
|
|
120
|
+
title: strongest(seen?.title, r.titleOverlap),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const judged = [...pages.values()].filter(p => p.text !== null);
|
|
124
|
+
if (judged.length === 0 || !judged.every(p => p.text < SAME_SITE_FLOOR))
|
|
125
|
+
return false;
|
|
126
|
+
if (judged.length > 1)
|
|
127
|
+
return true;
|
|
128
|
+
const { title } = judged[0];
|
|
129
|
+
return title !== null && title < SAME_SITE_FLOOR;
|
|
130
|
+
}
|
|
131
|
+
/** The higher of two overlaps, treating "could not judge" as no evidence. */
|
|
132
|
+
function strongest(a, b) {
|
|
133
|
+
if (typeof a !== 'number')
|
|
134
|
+
return typeof b === 'number' ? b : null;
|
|
135
|
+
if (typeof b !== 'number')
|
|
136
|
+
return a;
|
|
137
|
+
return Math.max(a, b);
|
|
138
|
+
}
|
|
139
|
+
/** What to do about it, when the caller says nothing: the `pr` path, which chose Pre itself. */
|
|
140
|
+
const DEFAULT_DIFFERENT_SITES_FIX = "re-run with --before pointing at this site's own deployment";
|
|
141
|
+
/**
|
|
142
|
+
* The one sentence a human needs when the two sides are not the same site.
|
|
143
|
+
*
|
|
144
|
+
* `beforeDetail` is how Pre was chosen ("production deployment for 26aa6cd"),
|
|
145
|
+
* absent when a caller was handed both URLs by hand and has no provenance to
|
|
146
|
+
* report. `fix` is the remedy, which is the caller's to name: telling someone
|
|
147
|
+
* to pass `--before` is right when the tool picked the baseline and wrong in
|
|
148
|
+
* the two-URL mode, where both sides came in as positional arguments and that
|
|
149
|
+
* flag is not how the command is invoked. Advice that does not apply to the
|
|
150
|
+
* mode you are in is the failure this project keeps finding — it is what sent
|
|
151
|
+
* someone to sign in to a macOS system service.
|
|
152
|
+
*/
|
|
153
|
+
export function differentSitesHint(beforeUrl, beforeDetail, afterUrl, fix = DEFAULT_DIFFERENT_SITES_FIX) {
|
|
154
|
+
const pre = beforeDetail ? `${beforeUrl} — ${beforeDetail}` : beforeUrl;
|
|
155
|
+
return `Pre (${pre}) and Post (${afterUrl}) share no wording on any route, so they are not the same site: ${fix}.`;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=sameness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sameness.js","sourceRoot":"","sources":["../src/sameness.ts"],"names":[],"mappings":"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"}
|
package/dist/sessions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAC1D,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;KAC1F,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAKrE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQ7D;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC,CAkBtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAC1D,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;KAC1F,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED,wBAAgB,WAAW,IAAI,MAAM,CAKpC;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,CAKrE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQ7D;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC,CAkBtE;AAED,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,GAAG,SAAS,CAkB5E"}
|
package/dist/sessions.js
CHANGED
|
@@ -61,9 +61,15 @@ export function cookiesForUrls(urls) {
|
|
|
61
61
|
export function resolveAuth(input) {
|
|
62
62
|
const headers = { ...(input.configHeaders || {}), ...(input.headers || {}) };
|
|
63
63
|
const bypass = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
64
|
+
// The bypass header alone is enough, and it is all we send. Asking for the
|
|
65
|
+
// cookie as well (`x-vercel-set-bypass-cookie: true`) makes the host set it
|
|
66
|
+
// through a redirect, which a client that keeps no cookie jar can never
|
|
67
|
+
// satisfy: the reachability probe uses plain `fetch`, so it looped until it
|
|
68
|
+
// threw and every protected preview was reported as unreachable. Measured
|
|
69
|
+
// against a live protected deployment on 2026-09-05 — with the one header,
|
|
70
|
+
// 200 and no redirect; with both, 307 until curl gave up at 50.
|
|
64
71
|
if (bypass && !headers['x-vercel-protection-bypass']) {
|
|
65
72
|
headers['x-vercel-protection-bypass'] = bypass;
|
|
66
|
-
headers['x-vercel-set-bypass-cookie'] = 'true';
|
|
67
73
|
}
|
|
68
74
|
const cookies = [
|
|
69
75
|
...cookiesForUrls(input.urls),
|
package/dist/sessions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
|
package/dist/shift.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical displacement between two captures.
|
|
3
|
+
*
|
|
4
|
+
* A padding change near the top of a page moves everything below it. Pixel
|
|
5
|
+
* diffing counts every moved pixel as changed, so a change a designer would
|
|
6
|
+
* call "slightly roomier" reads as 60-90% of the page repainted — and above
|
|
7
|
+
* CROP_MAX_RATIO no crop is produced at all, so the most dramatic-looking
|
|
8
|
+
* result gives a reviewer the least to look at.
|
|
9
|
+
*
|
|
10
|
+
* A layout shift always has a start: content above the changed element stays
|
|
11
|
+
* put and content below it moves by a constant amount. Recovering that pair
|
|
12
|
+
* (how far, from where) turns the repaint back into a sentence — "content
|
|
13
|
+
* shifted down 48px" — and lets the diff run on aligned images, which is the
|
|
14
|
+
* change the branch actually made.
|
|
15
|
+
*
|
|
16
|
+
* Rows are matched by hash rather than correlated numerically: a shifted page
|
|
17
|
+
* re-renders its rows identically, so exact matches carry the signal and cost
|
|
18
|
+
* one pass over the pixels.
|
|
19
|
+
*/
|
|
20
|
+
import { PNG } from 'pngjs';
|
|
21
|
+
export interface ShiftCandidate {
|
|
22
|
+
/** Device pixels the Post content moved down by; negative means up. */
|
|
23
|
+
dy: number;
|
|
24
|
+
/** First row (in Pre coordinates) that moved. Rows above it stayed put. */
|
|
25
|
+
from: number;
|
|
26
|
+
/** Rows the offset explains, as a fraction of all distinctive rows. */
|
|
27
|
+
coverage: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* FNV-1a over each row's bytes. Distinct content gives distinct hashes; the
|
|
31
|
+
* collision rate over a few thousand rows is negligible, and a collision can
|
|
32
|
+
* only add a stray vote to an offset that other rows have to agree on anyway.
|
|
33
|
+
*/
|
|
34
|
+
export declare function rowHashes(png: PNG): Uint32Array;
|
|
35
|
+
/**
|
|
36
|
+
* Find a single vertical displacement that explains the difference between two
|
|
37
|
+
* equally sized images, or null when none does.
|
|
38
|
+
*
|
|
39
|
+
* Rows that repeat (blank space, flat backgrounds, rules) are dropped first:
|
|
40
|
+
* they match every offset equally and would otherwise outvote the content.
|
|
41
|
+
* What remains votes for the offset that maps it from Pre to Post, and the
|
|
42
|
+
* winner has to be supported by enough rows to mean something.
|
|
43
|
+
*/
|
|
44
|
+
export declare function detectShift(before: PNG, after: PNG): ShiftCandidate | null;
|
|
45
|
+
/**
|
|
46
|
+
* Rows Post has that Pre never did. A downward shift means something new
|
|
47
|
+
* pushed the page down, and those rows are that something.
|
|
48
|
+
*/
|
|
49
|
+
export declare function insertedBand(shift: ShiftCandidate): {
|
|
50
|
+
y: number;
|
|
51
|
+
height: number;
|
|
52
|
+
} | null;
|
|
53
|
+
/**
|
|
54
|
+
* Rebuild Pre in Post's coordinates: content above the shift stays where it
|
|
55
|
+
* is, content below it moves down by `dy`, and an insertion leaves a gap.
|
|
56
|
+
*
|
|
57
|
+
* Aligning this way round rather than pulling Post back is what makes an
|
|
58
|
+
* insertion visible. Mapping every Pre row onto a Post row steps straight over
|
|
59
|
+
* the rows Post gained, so a banner nobody had seen before would contribute
|
|
60
|
+
* nothing and the report would call it "nothing else changed". Left as
|
|
61
|
+
* background, whatever Post put there reads as what it is: new content.
|
|
62
|
+
*
|
|
63
|
+
* It also means the Post image published beside it is the real capture rather
|
|
64
|
+
* than a synthesis, and the re-spaced side is the one being compared against.
|
|
65
|
+
*/
|
|
66
|
+
export declare function alignBefore(before: PNG, shift: ShiftCandidate, pad: [number, number, number]): PNG;
|
|
67
|
+
//# sourceMappingURL=shift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shift.d.ts","sourceRoot":"","sources":["../src/shift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAS5B,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW,CAc/C;AAQD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,cAAc,GAAG,IAAI,CAiE1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAExF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAoBlG"}
|
package/dist/shift.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vertical displacement between two captures.
|
|
3
|
+
*
|
|
4
|
+
* A padding change near the top of a page moves everything below it. Pixel
|
|
5
|
+
* diffing counts every moved pixel as changed, so a change a designer would
|
|
6
|
+
* call "slightly roomier" reads as 60-90% of the page repainted — and above
|
|
7
|
+
* CROP_MAX_RATIO no crop is produced at all, so the most dramatic-looking
|
|
8
|
+
* result gives a reviewer the least to look at.
|
|
9
|
+
*
|
|
10
|
+
* A layout shift always has a start: content above the changed element stays
|
|
11
|
+
* put and content below it moves by a constant amount. Recovering that pair
|
|
12
|
+
* (how far, from where) turns the repaint back into a sentence — "content
|
|
13
|
+
* shifted down 48px" — and lets the diff run on aligned images, which is the
|
|
14
|
+
* change the branch actually made.
|
|
15
|
+
*
|
|
16
|
+
* Rows are matched by hash rather than correlated numerically: a shifted page
|
|
17
|
+
* re-renders its rows identically, so exact matches carry the signal and cost
|
|
18
|
+
* one pass over the pixels.
|
|
19
|
+
*/
|
|
20
|
+
import { PNG } from 'pngjs';
|
|
21
|
+
/** A row hash seen more often than this in either image carries no position information. */
|
|
22
|
+
const MAX_ROW_REPEATS = 4;
|
|
23
|
+
/** Below this many distinctive rows there is not enough signal to trust an offset. */
|
|
24
|
+
const MIN_DISTINCTIVE_ROWS = 16;
|
|
25
|
+
/** An offset supported by fewer rows than this is noise. */
|
|
26
|
+
const MIN_MOVED_ROWS = 8;
|
|
27
|
+
/**
|
|
28
|
+
* FNV-1a over each row's bytes. Distinct content gives distinct hashes; the
|
|
29
|
+
* collision rate over a few thousand rows is negligible, and a collision can
|
|
30
|
+
* only add a stray vote to an offset that other rows have to agree on anyway.
|
|
31
|
+
*/
|
|
32
|
+
export function rowHashes(png) {
|
|
33
|
+
const { width, height, data } = png;
|
|
34
|
+
const stride = width * 4;
|
|
35
|
+
const out = new Uint32Array(height);
|
|
36
|
+
for (let y = 0; y < height; y++) {
|
|
37
|
+
let h = 0x811c9dc5;
|
|
38
|
+
const start = y * stride;
|
|
39
|
+
for (let i = start; i < start + stride; i++) {
|
|
40
|
+
h ^= data[i];
|
|
41
|
+
h = Math.imul(h, 0x01000193);
|
|
42
|
+
}
|
|
43
|
+
out[y] = h >>> 0;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
function countHashes(hashes) {
|
|
48
|
+
const counts = new Map();
|
|
49
|
+
for (const h of hashes)
|
|
50
|
+
counts.set(h, (counts.get(h) ?? 0) + 1);
|
|
51
|
+
return counts;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Find a single vertical displacement that explains the difference between two
|
|
55
|
+
* equally sized images, or null when none does.
|
|
56
|
+
*
|
|
57
|
+
* Rows that repeat (blank space, flat backgrounds, rules) are dropped first:
|
|
58
|
+
* they match every offset equally and would otherwise outvote the content.
|
|
59
|
+
* What remains votes for the offset that maps it from Pre to Post, and the
|
|
60
|
+
* winner has to be supported by enough rows to mean something.
|
|
61
|
+
*/
|
|
62
|
+
export function detectShift(before, after) {
|
|
63
|
+
if (before.width !== after.width || before.height !== after.height)
|
|
64
|
+
return null;
|
|
65
|
+
const height = before.height;
|
|
66
|
+
const beforeHashes = rowHashes(before);
|
|
67
|
+
const afterHashes = rowHashes(after);
|
|
68
|
+
const beforeCounts = countHashes(beforeHashes);
|
|
69
|
+
const afterCounts = countHashes(afterHashes);
|
|
70
|
+
const distinctive = (h) => (beforeCounts.get(h) ?? 0) > 0 &&
|
|
71
|
+
(beforeCounts.get(h) ?? 0) <= MAX_ROW_REPEATS &&
|
|
72
|
+
(afterCounts.get(h) ?? 0) <= MAX_ROW_REPEATS;
|
|
73
|
+
// Where each distinctive row sits in Pre, so Post rows can look it up.
|
|
74
|
+
const beforeRows = new Map();
|
|
75
|
+
for (let y = 0; y < height; y++) {
|
|
76
|
+
const h = beforeHashes[y];
|
|
77
|
+
if (!distinctive(h))
|
|
78
|
+
continue;
|
|
79
|
+
const list = beforeRows.get(h);
|
|
80
|
+
if (list)
|
|
81
|
+
list.push(y);
|
|
82
|
+
else
|
|
83
|
+
beforeRows.set(h, [y]);
|
|
84
|
+
}
|
|
85
|
+
const votes = new Map();
|
|
86
|
+
let distinctiveRows = 0;
|
|
87
|
+
for (let y = 0; y < height; y++) {
|
|
88
|
+
const h = afterHashes[y];
|
|
89
|
+
if (!distinctive(h))
|
|
90
|
+
continue;
|
|
91
|
+
distinctiveRows++;
|
|
92
|
+
const origins = beforeRows.get(h);
|
|
93
|
+
if (!origins)
|
|
94
|
+
continue;
|
|
95
|
+
for (const origin of origins) {
|
|
96
|
+
const d = y - origin;
|
|
97
|
+
votes.set(d, (votes.get(d) ?? 0) + 1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (distinctiveRows < MIN_DISTINCTIVE_ROWS)
|
|
101
|
+
return null;
|
|
102
|
+
let dy = 0;
|
|
103
|
+
let moved = 0;
|
|
104
|
+
for (const [d, count] of votes) {
|
|
105
|
+
if (d === 0)
|
|
106
|
+
continue;
|
|
107
|
+
if (count > moved) {
|
|
108
|
+
dy = d;
|
|
109
|
+
moved = count;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (dy === 0 || moved < MIN_MOVED_ROWS)
|
|
113
|
+
return null;
|
|
114
|
+
// Where the movement starts: the first Pre row that maps to Post at the
|
|
115
|
+
// winning offset and never goes back to sitting still. Everything above it
|
|
116
|
+
// is content the change did not move.
|
|
117
|
+
const stayed = new Set();
|
|
118
|
+
const shifted = new Set();
|
|
119
|
+
for (let y = 0; y < height; y++) {
|
|
120
|
+
const h = beforeHashes[y];
|
|
121
|
+
if (!distinctive(h))
|
|
122
|
+
continue;
|
|
123
|
+
if (afterHashes[y] === h)
|
|
124
|
+
stayed.add(y);
|
|
125
|
+
if (y + dy >= 0 && y + dy < height && afterHashes[y + dy] === h)
|
|
126
|
+
shifted.add(y);
|
|
127
|
+
}
|
|
128
|
+
let from = height;
|
|
129
|
+
for (let y = height - 1; y >= 0; y--) {
|
|
130
|
+
if (shifted.has(y))
|
|
131
|
+
from = y;
|
|
132
|
+
else if (stayed.has(y))
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
if (from >= height)
|
|
136
|
+
return null;
|
|
137
|
+
return { dy, from, coverage: moved / distinctiveRows };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Rows Post has that Pre never did. A downward shift means something new
|
|
141
|
+
* pushed the page down, and those rows are that something.
|
|
142
|
+
*/
|
|
143
|
+
export function insertedBand(shift) {
|
|
144
|
+
return shift.dy > 0 ? { y: shift.from, height: shift.dy } : null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Rebuild Pre in Post's coordinates: content above the shift stays where it
|
|
148
|
+
* is, content below it moves down by `dy`, and an insertion leaves a gap.
|
|
149
|
+
*
|
|
150
|
+
* Aligning this way round rather than pulling Post back is what makes an
|
|
151
|
+
* insertion visible. Mapping every Pre row onto a Post row steps straight over
|
|
152
|
+
* the rows Post gained, so a banner nobody had seen before would contribute
|
|
153
|
+
* nothing and the report would call it "nothing else changed". Left as
|
|
154
|
+
* background, whatever Post put there reads as what it is: new content.
|
|
155
|
+
*
|
|
156
|
+
* It also means the Post image published beside it is the real capture rather
|
|
157
|
+
* than a synthesis, and the re-spaced side is the one being compared against.
|
|
158
|
+
*/
|
|
159
|
+
export function alignBefore(before, shift, pad) {
|
|
160
|
+
const { width, height } = before;
|
|
161
|
+
const out = new PNG({ width, height });
|
|
162
|
+
const stride = width * 4;
|
|
163
|
+
const gap = insertedBand(shift);
|
|
164
|
+
for (let y = 0; y < height; y++) {
|
|
165
|
+
// Above the shift the two sides agree on position; below it Pre sits `dy`
|
|
166
|
+
// higher than Post does.
|
|
167
|
+
const source = y < shift.from ? y : y - shift.dy;
|
|
168
|
+
const inGap = gap !== null && y >= gap.y && y < gap.y + gap.height;
|
|
169
|
+
const target = y * stride;
|
|
170
|
+
if (!inGap && source >= 0 && source < height) {
|
|
171
|
+
before.data.copy(out.data, target, source * stride, source * stride + stride);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
for (let i = target; i < target + stride; i += 4) {
|
|
175
|
+
out.data[i] = pad[0];
|
|
176
|
+
out.data[i + 1] = pad[1];
|
|
177
|
+
out.data[i + 2] = pad[2];
|
|
178
|
+
out.data[i + 3] = 255;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=shift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shift.js","sourceRoot":"","sources":["../src/shift.ts"],"names":[],"mappings":"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"}
|