ssrwire 0.2.0 → 0.4.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 +47 -1
- package/CONTRIBUTING.md +3 -1
- package/PUBLISHING.md +15 -15
- package/README.md +179 -29
- package/dist/analyze.d.ts.map +1 -1
- package/dist/analyze.js +162 -6
- package/dist/analyze.js.map +1 -1
- package/dist/audit-report.d.ts +8 -0
- package/dist/audit-report.d.ts.map +1 -0
- package/dist/audit-report.js +243 -0
- package/dist/audit-report.js.map +1 -0
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +2 -0
- package/dist/audit.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +77 -10
- package/dist/cli.js.map +1 -1
- package/dist/compare.d.ts +6 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +720 -0
- package/dist/compare.js.map +1 -0
- package/dist/comparison-reporters.d.ts +9 -0
- package/dist/comparison-reporters.d.ts.map +1 -0
- package/dist/comparison-reporters.js +223 -0
- package/dist/comparison-reporters.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -1
- package/dist/config.js.map +1 -1
- package/dist/http-probe.d.ts.map +1 -1
- package/dist/http-probe.js +4 -0
- package/dist/http-probe.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/redact.d.ts.map +1 -1
- package/dist/redact.js +6 -0
- package/dist/redact.js.map +1 -1
- package/dist/reporters.d.ts.map +1 -1
- package/dist/reporters.js +27 -0
- package/dist/reporters.js.map +1 -1
- package/dist/social.d.ts +14 -0
- package/dist/social.d.ts.map +1 -0
- package/dist/social.js +88 -0
- package/dist/social.js.map +1 -0
- package/dist/stability.d.ts.map +1 -1
- package/dist/stability.js +84 -4
- package/dist/stability.js.map +1 -1
- package/dist/stream-parser.d.ts.map +1 -1
- package/dist/stream-parser.js +21 -1
- package/dist/stream-parser.js.map +1 -1
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -1
- package/examples/github-actions.yml +2 -2
- package/examples/ssrwire.config.yml +8 -2
- package/package.json +5 -2
- package/src/analyze.ts +208 -7
- package/src/audit-report.ts +269 -0
- package/src/audit.ts +2 -0
- package/src/cli.ts +106 -12
- package/src/compare.ts +949 -0
- package/src/comparison-reporters.ts +276 -0
- package/src/config.ts +19 -1
- package/src/http-probe.ts +4 -0
- package/src/index.ts +29 -0
- package/src/redact.ts +6 -0
- package/src/reporters.ts +46 -0
- package/src/social.ts +116 -0
- package/src/stability.ts +123 -4
- package/src/stream-parser.ts +31 -1
- package/src/types.ts +117 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,50 @@ All notable changes to SSRWire are documented here. The project follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2026-09-01
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Offline `ssrwire compare` for two redacted JSON audits, with stable target IDs
|
|
13
|
+
for matching the same route across production and preview origins.
|
|
14
|
+
- Regression, fixed, and neutral-change classification for policy findings,
|
|
15
|
+
completion, HTTP delivery, metadata values and locations, agent coverage, and
|
|
16
|
+
redirect evidence.
|
|
17
|
+
- Dual-floor median timing comparisons with configurable absolute and relative
|
|
18
|
+
thresholds.
|
|
19
|
+
- Terminal and deterministic JSON comparison reports plus a self-contained,
|
|
20
|
+
script-free HTML wire waterfall.
|
|
21
|
+
- Public comparison, report-validation, and comparison-reporter APIs.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- JSON audits now include an explicit `schemaVersion: 1` persisted-report
|
|
26
|
+
contract independent of the SSRWire package version.
|
|
27
|
+
- Target objects accept an optional unique `id`; exact URL matching remains the
|
|
28
|
+
fallback when an ID is absent.
|
|
29
|
+
|
|
30
|
+
## [0.3.0] - 2026-08-28
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Streamed capture for core Open Graph and Twitter Card metadata with arrival
|
|
35
|
+
time, observed byte position, document location, bounded repeated values, and
|
|
36
|
+
report redaction.
|
|
37
|
+
- Opt-in `require.openGraph` and `require.twitterCard` target contracts with
|
|
38
|
+
missing-field, invalid-URL, duplicate/conflict, and head/body delivery
|
|
39
|
+
findings.
|
|
40
|
+
- A terminal social-preview readiness table and public social metadata signal
|
|
41
|
+
types in JSON and the programmatic API.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Enabled social contracts now participate in required-signal timing,
|
|
46
|
+
cross-agent comparison, and repeated-sample stability analysis.
|
|
47
|
+
- Twitter Card readiness prefers native Twitter metadata and falls back to the
|
|
48
|
+
corresponding Open Graph title, description, and image.
|
|
49
|
+
- Multiple `og:image` values are retained in document order without being
|
|
50
|
+
treated as conflicting scalar metadata.
|
|
51
|
+
|
|
8
52
|
## [0.2.0] - 2026-08-24
|
|
9
53
|
|
|
10
54
|
### Added
|
|
@@ -36,6 +80,8 @@ All notable changes to SSRWire are documented here. The project follows
|
|
|
36
80
|
- Terminal, JSON, and SARIF reports with CI-safe exit codes.
|
|
37
81
|
- YAML configuration, one-off URL checks, Docker support, and GitHub Actions examples.
|
|
38
82
|
|
|
39
|
-
[Unreleased]: https://github.com/lame13/ssrwire/compare/v0.
|
|
83
|
+
[Unreleased]: https://github.com/lame13/ssrwire/compare/v0.4.0...HEAD
|
|
84
|
+
[0.4.0]: https://github.com/lame13/ssrwire/compare/v0.3.0...v0.4.0
|
|
85
|
+
[0.3.0]: https://github.com/lame13/ssrwire/compare/v0.2.0...v0.3.0
|
|
40
86
|
[0.2.0]: https://github.com/lame13/ssrwire/compare/v0.1.0...v0.2.0
|
|
41
87
|
[0.1.0]: https://github.com/lame13/ssrwire/releases/tag/v0.1.0
|
package/CONTRIBUTING.md
CHANGED
|
@@ -26,12 +26,14 @@ before opening a pull request, then run `npm run check` again.
|
|
|
26
26
|
Keep each change narrow. Include tests for behavior changes, especially for:
|
|
27
27
|
|
|
28
28
|
- response chunk boundaries and elements split across chunks;
|
|
29
|
+
- persisted audit-report validation, target matching, and comparison classification;
|
|
29
30
|
- redirects, timeouts, aborted bodies, and size limits;
|
|
30
31
|
- malformed, duplicated, late, or body-located metadata;
|
|
32
|
+
- Open Graph and Twitter Card requirements, fallbacks, arrays, and URL values;
|
|
31
33
|
- user-agent differences and comparison findings;
|
|
32
34
|
- repeated-sample ordering, aggregation, and instability classification;
|
|
33
35
|
- redaction of configured header values;
|
|
34
|
-
- terminal, JSON, SARIF, and exit-code behavior.
|
|
36
|
+
- terminal, JSON, SARIF, comparison HTML, and exit-code behavior.
|
|
35
37
|
|
|
36
38
|
Do not make timing tests depend on exact millisecond values. Shared runners and
|
|
37
39
|
local machines have unavoidable scheduling variance. Test ordering,
|
package/PUBLISHING.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Publish SSRWire 0.
|
|
1
|
+
# Publish SSRWire 0.4.0 from a local machine
|
|
2
2
|
|
|
3
3
|
This repository intentionally includes no npm publishing workflow. Publish from
|
|
4
4
|
a foreground local terminal only after the GitHub `CI` workflow passes. Do not
|
|
@@ -10,7 +10,7 @@ request, and do not use an administrator bypass or a direct push to `main`.
|
|
|
10
10
|
|
|
11
11
|
## 1. Update the existing repository
|
|
12
12
|
|
|
13
|
-
Work from a clean clone of the existing public repository. Copy the 0.
|
|
13
|
+
Work from a clean clone of the existing public repository. Copy the 0.4.0
|
|
14
14
|
source files into that clone while preserving its `.git` directory.
|
|
15
15
|
|
|
16
16
|
```bash
|
|
@@ -18,7 +18,7 @@ cd ssrwire
|
|
|
18
18
|
git switch main
|
|
19
19
|
git pull --ff-only origin main
|
|
20
20
|
git status --short
|
|
21
|
-
git switch -c release/0.
|
|
21
|
+
git switch -c release/0.4.0
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
`git status --short` must be empty before creating the release branch and
|
|
@@ -36,7 +36,7 @@ npm pack --dry-run
|
|
|
36
36
|
node dist/bin.js --version
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
The final command must print `0.
|
|
39
|
+
The final command must print `0.4.0`. Inspect the dry-run file list. It must not
|
|
40
40
|
contain `.env`, `.github`, `node_modules`, `test`, ZIP files, or tarballs.
|
|
41
41
|
|
|
42
42
|
Review the release diff and version references:
|
|
@@ -45,7 +45,7 @@ Review the release diff and version references:
|
|
|
45
45
|
git diff --check
|
|
46
46
|
git diff --stat
|
|
47
47
|
git diff -- package.json package-lock.json CHANGELOG.md README.md PUBLISHING.md
|
|
48
|
-
rg '0\.
|
|
48
|
+
rg '0\.3\.0' README.md examples package.json package-lock.json scripts src test
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
The final search should return nothing. Historical entries in `CHANGELOG.md`
|
|
@@ -58,10 +58,10 @@ gh auth status -h github.com || gh auth login -h github.com --web
|
|
|
58
58
|
git add --all
|
|
59
59
|
git diff --cached --check
|
|
60
60
|
git diff --cached --stat
|
|
61
|
-
git commit -m "feat: release SSRWire 0.
|
|
62
|
-
git push --set-upstream origin release/0.
|
|
63
|
-
gh pr create --base main --head release/0.
|
|
64
|
-
PR_NUMBER="$(gh pr view release/0.
|
|
61
|
+
git commit -m "feat: release SSRWire 0.4.0"
|
|
62
|
+
git push --set-upstream origin release/0.4.0
|
|
63
|
+
gh pr create --base main --head release/0.4.0 --fill
|
|
64
|
+
PR_NUMBER="$(gh pr view release/0.4.0 --json number --jq .number)"
|
|
65
65
|
test -n "$PR_NUMBER"
|
|
66
66
|
gh pr checks "$PR_NUMBER" --watch --fail-fast
|
|
67
67
|
```
|
|
@@ -102,8 +102,8 @@ npm config get registry
|
|
|
102
102
|
npm config get provenance
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
The published version and `latest` tag must still be `0.
|
|
106
|
-
reports `0.
|
|
105
|
+
The published version and `latest` tag must still be `0.3.0`. If npm already
|
|
106
|
+
reports `0.4.0`, stop: never reuse a version that npm accepted.
|
|
107
107
|
|
|
108
108
|
In the npm package settings, select **Require two-factor authentication and
|
|
109
109
|
disallow tokens**. npm documents this as the strongest package publishing
|
|
@@ -132,7 +132,7 @@ or add an npm credential to the repository or GitHub Actions. The package-level
|
|
|
132
132
|
"disallow tokens" setting ensures that publication remains interactive.
|
|
133
133
|
|
|
134
134
|
If npm's publish-time scanning delays package visibility, wait. Do not publish
|
|
135
|
-
`0.
|
|
135
|
+
`0.4.0` again or change the tag to work around propagation.
|
|
136
136
|
|
|
137
137
|
## 6. Tag the exact published commit
|
|
138
138
|
|
|
@@ -140,9 +140,9 @@ If npm's publish-time scanning delays package visibility, wait. Do not publish
|
|
|
140
140
|
node scripts/clean.mjs
|
|
141
141
|
rm -rf node_modules/.vite
|
|
142
142
|
git status --short
|
|
143
|
-
git tag -a v0.
|
|
144
|
-
git push origin v0.
|
|
145
|
-
gh release create v0.
|
|
143
|
+
git tag -a v0.4.0 -m "SSRWire v0.4.0"
|
|
144
|
+
git push origin v0.4.0
|
|
145
|
+
gh release create v0.4.0 --generate-notes --title "SSRWire v0.4.0"
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
`git status --short` must print nothing before tagging.
|
package/README.md
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/ssrwire)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
Inspect streamed SSR HTML, metadata timing, and crawler-specific
|
|
8
|
-
the command line.
|
|
7
|
+
Inspect streamed SSR HTML, SEO and social metadata timing, and crawler-specific
|
|
8
|
+
delivery from the command line.
|
|
9
9
|
|
|
10
10
|
SSRWire makes a real HTTP request for each selected user-agent profile, reads
|
|
11
|
-
the response incrementally, and records when important SEO
|
|
12
|
-
observable to its parser. It reports their elapsed time,
|
|
13
|
-
position, and document location without launching a browser or
|
|
14
|
-
JavaScript.
|
|
11
|
+
the response incrementally, and records when important SEO and social-preview
|
|
12
|
+
signals become observable to its parser. It reports their elapsed time,
|
|
13
|
+
observed byte position, and document location without launching a browser or
|
|
14
|
+
executing JavaScript.
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
npx ssrwire https://example.com/product
|
|
@@ -25,7 +25,8 @@ Modern SSR output is not always one complete HTML document delivered at once:
|
|
|
25
25
|
- a framework may intentionally stream metadata into `<body>` for a capable
|
|
26
26
|
crawler while blocking for an HTML-limited bot;
|
|
27
27
|
- browser, search-crawler, and social-crawler user agents may receive different
|
|
28
|
-
titles, canonicals, robots directives, redirects, or
|
|
28
|
+
titles, canonicals, social-preview metadata, robots directives, redirects, or
|
|
29
|
+
statuses;
|
|
29
30
|
- the same URL and user agent may receive inconsistent SSR output between requests;
|
|
30
31
|
- an interrupted or oversized stream may never deliver the expected elements;
|
|
31
32
|
- a working hydrated page can hide thin or incomplete source HTML.
|
|
@@ -84,6 +85,65 @@ npx ssrwire check \
|
|
|
84
85
|
The root command and `check` are equivalent, so `npx ssrwire URL` is the short
|
|
85
86
|
form of `npx ssrwire check URL`.
|
|
86
87
|
|
|
88
|
+
## Compare deployments
|
|
89
|
+
|
|
90
|
+
SSRWire can compare two JSON audits without making more network requests. Give
|
|
91
|
+
the same logical target a stable `id` in each environment so reports can match
|
|
92
|
+
across different origins:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
# production.yml
|
|
96
|
+
targets:
|
|
97
|
+
- id: home
|
|
98
|
+
url: https://www.example.com/
|
|
99
|
+
- id: pricing
|
|
100
|
+
url: https://www.example.com/pricing/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
# preview.yml
|
|
105
|
+
targets:
|
|
106
|
+
- id: home
|
|
107
|
+
url: https://preview.example.net/
|
|
108
|
+
- id: pricing
|
|
109
|
+
url: https://preview.example.net/pricing/
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Capture and compare the already-redacted reports:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx ssrwire check --config production.yml --format json --output production.json
|
|
116
|
+
npx ssrwire check --config preview.yml --format json --output preview.json
|
|
117
|
+
|
|
118
|
+
npx ssrwire compare production.json preview.json
|
|
119
|
+
npx ssrwire compare production.json preview.json \
|
|
120
|
+
--format html \
|
|
121
|
+
--output ssrwire-diff.html
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The comparison classifies candidate-only warning/error findings and newly
|
|
125
|
+
incomplete probes as regressions, resolved findings and material timing
|
|
126
|
+
improvements as fixed, and response or metadata differences as neutral changes.
|
|
127
|
+
A metadata change becomes a regression when it causes a candidate policy
|
|
128
|
+
finding, such as required metadata disappearing or head-only crawler metadata
|
|
129
|
+
moving into the body.
|
|
130
|
+
|
|
131
|
+
Timing regressions use per-agent medians and require both an absolute increase
|
|
132
|
+
over 250 ms and a relative increase over 25% by default. Both floors are
|
|
133
|
+
configurable on `compare`; small timing differences remain visible in the HTML
|
|
134
|
+
waterfall without making CI noisy. `--fail-on regression` is the comparison
|
|
135
|
+
default, while `--fail-on never` always exits successfully after valid reports
|
|
136
|
+
are compared.
|
|
137
|
+
|
|
138
|
+
The HTML report is one self-contained, script-free file with synchronized
|
|
139
|
+
baseline and candidate milestones. It never embeds raw response HTML. SSRWire
|
|
140
|
+
does not create or update baseline files automatically.
|
|
141
|
+
|
|
142
|
+
Reports without target IDs match by exact target URL. IDs must be unique within
|
|
143
|
+
one report, so an ID mismatch is shown as one removed and one added target
|
|
144
|
+
instead of being guessed. Comparison requires the explicit `schemaVersion: 1`
|
|
145
|
+
audit contract emitted by SSRWire 0.4.0.
|
|
146
|
+
|
|
87
147
|
## What it observes
|
|
88
148
|
|
|
89
149
|
For each target, agent, and configured sample, SSRWire captures:
|
|
@@ -91,8 +151,8 @@ For each target, agent, and configured sample, SSRWire captures:
|
|
|
91
151
|
- response status, final URL, redirect chain, and an allowlisted response-header snapshot;
|
|
92
152
|
- time to response headers, first response-body bytes, and completed body;
|
|
93
153
|
- total bytes delivered to the stream parser and a body fingerprint;
|
|
94
|
-
- title, meta description, canonical, meta robots,
|
|
95
|
-
text, and JSON-LD blocks;
|
|
154
|
+
- title, meta description, canonical, meta robots, Open Graph, Twitter Card,
|
|
155
|
+
H1, first main-content text, and JSON-LD blocks;
|
|
96
156
|
- elapsed arrival time, observed byte position, and `head`/`body` location for
|
|
97
157
|
each signal;
|
|
98
158
|
- clean completion, timeout, network failure, invalid response, or configured
|
|
@@ -107,10 +167,12 @@ It then checks:
|
|
|
107
167
|
| Missing title | Error |
|
|
108
168
|
| Missing description, canonical, H1, or main text | Warning |
|
|
109
169
|
| Duplicate or conflicting title, description, canonical, or robots values | Warning |
|
|
170
|
+
| Missing an enabled Open Graph or Twitter Card contract | Warning |
|
|
171
|
+
| Invalid social metadata URL or conflicting scalar social metadata | Warning |
|
|
110
172
|
| Invalid JSON-LD | Warning |
|
|
111
173
|
| JSON-LD block/count exceeds the bounded analysis budget | Warning |
|
|
112
|
-
| Critical metadata in `<body>` for a profile that requires head metadata | Error |
|
|
113
|
-
| Status, final URL, title, canonical, or
|
|
174
|
+
| Critical or enabled social metadata in `<body>` for a profile that requires head metadata | Error |
|
|
175
|
+
| Status, final URL, title, canonical, robots, or enabled social metadata drift between profiles | Warning |
|
|
114
176
|
| Completion, status, final URL, or redirect-chain drift between samples | Warning |
|
|
115
177
|
| Metadata value or document-location drift between complete samples | Warning |
|
|
116
178
|
| Exact body fingerprint drift without metadata drift | Information |
|
|
@@ -162,6 +224,41 @@ agents:
|
|
|
162
224
|
requiresHeadMetadata: true
|
|
163
225
|
```
|
|
164
226
|
|
|
227
|
+
## Social preview metadata
|
|
228
|
+
|
|
229
|
+
Every probe captures these bounded, ordered metadata signals when they arrive
|
|
230
|
+
before completion or termination:
|
|
231
|
+
|
|
232
|
+
- Open Graph: `og:title`, `og:type`, `og:url`, `og:image`, and
|
|
233
|
+
`og:description`;
|
|
234
|
+
- Twitter Card: `twitter:card`, `twitter:title`, `twitter:description`, and
|
|
235
|
+
`twitter:image`.
|
|
236
|
+
|
|
237
|
+
SSRWire accepts either the conventional `property` attribute or a `name`
|
|
238
|
+
attribute for those keys. Each captured value carries the same arrival time,
|
|
239
|
+
observed byte position, and document location as the existing metadata
|
|
240
|
+
signals. The terminal report shows a compact readiness table whenever social
|
|
241
|
+
metadata is observed or required, while JSON retains every captured value.
|
|
242
|
+
|
|
243
|
+
Social policy is opt-in per target. `openGraph: true` requires the four basic
|
|
244
|
+
[Open Graph protocol](https://ogp.me/) properties: title, type, URL, and image.
|
|
245
|
+
The `twitterCard: true` option requires `twitter:card` plus a usable title,
|
|
246
|
+
description, and image; SSRWire prefers the corresponding `twitter:*` value
|
|
247
|
+
and falls back to `og:title`, `og:description`, or `og:image`. These are
|
|
248
|
+
explicit SSRWire audit contracts, not a claim that a social platform will
|
|
249
|
+
render a particular preview.
|
|
250
|
+
|
|
251
|
+
Enabled contracts also participate in critical-signal timing, head/body
|
|
252
|
+
policy, cross-agent drift, and repeated-sample stability checks. URL-valued
|
|
253
|
+
fields must be absolute HTTP or HTTPS URLs. Open Graph permits multiple images,
|
|
254
|
+
so SSRWire retains them in order without treating the array as a scalar
|
|
255
|
+
conflict; the first non-empty image satisfies readiness.
|
|
256
|
+
|
|
257
|
+
When both options are false, SSRWire still records and reports raw social
|
|
258
|
+
signals but emits no social-policy or social-drift findings. It does not fetch
|
|
259
|
+
images, verify dimensions or media types, execute JavaScript, or simulate a
|
|
260
|
+
platform's rendered preview.
|
|
261
|
+
|
|
165
262
|
## Configuration
|
|
166
263
|
|
|
167
264
|
SSRWire automatically looks for `ssrwire.config.yml`,
|
|
@@ -170,7 +267,8 @@ takes precedence.
|
|
|
170
267
|
|
|
171
268
|
```yaml
|
|
172
269
|
targets:
|
|
173
|
-
-
|
|
270
|
+
- id: home
|
|
271
|
+
url: https://example.com/
|
|
174
272
|
expectedStatus: 200
|
|
175
273
|
expectedFinalUrl: https://example.com/
|
|
176
274
|
require:
|
|
@@ -179,10 +277,13 @@ targets:
|
|
|
179
277
|
canonical: true
|
|
180
278
|
h1: true
|
|
181
279
|
mainText: true
|
|
280
|
+
openGraph: true
|
|
281
|
+
twitterCard: true
|
|
182
282
|
maxFirstByteMs: 1200
|
|
183
283
|
maxCriticalMs: 2500
|
|
184
284
|
|
|
185
|
-
-
|
|
285
|
+
- id: not-found
|
|
286
|
+
url: https://example.com/not-found/
|
|
186
287
|
expectedStatus: [404]
|
|
187
288
|
require:
|
|
188
289
|
title: true
|
|
@@ -190,6 +291,8 @@ targets:
|
|
|
190
291
|
canonical: false
|
|
191
292
|
h1: true
|
|
192
293
|
mainText: true
|
|
294
|
+
openGraph: false
|
|
295
|
+
twitterCard: false
|
|
193
296
|
|
|
194
297
|
agents:
|
|
195
298
|
- browser
|
|
@@ -214,10 +317,15 @@ targets:
|
|
|
214
317
|
- https://example.com/pricing/
|
|
215
318
|
```
|
|
216
319
|
|
|
320
|
+
Use the object form with a stable `id` when reports from different origins will
|
|
321
|
+
be compared. IDs are 1–64 ASCII letters, digits, dots, underscores, or hyphens,
|
|
322
|
+
and must start with a letter or digit.
|
|
323
|
+
|
|
217
324
|
Defaults:
|
|
218
325
|
|
|
219
326
|
- expected status: `200`;
|
|
220
327
|
- title, description, canonical, H1, and main text: required;
|
|
328
|
+
- Open Graph and Twitter Card contracts: disabled;
|
|
221
329
|
- agents: `browser`, `googlebot`, `bingbot`, and `twitterbot`;
|
|
222
330
|
- timeout: 15 seconds per probe;
|
|
223
331
|
- response limit: 10 MiB;
|
|
@@ -262,11 +370,11 @@ The final response must declare `text/html` or `application/xhtml+xml` as its
|
|
|
262
370
|
sniff headerless, JSON, text, or binary responses for HTML-looking fragments.
|
|
263
371
|
|
|
264
372
|
To keep hostile or accidentally huge pages bounded, SSRWire retains at most
|
|
265
|
-
256 signals of each repeated metadata kind,
|
|
266
|
-
and captures at most 1,048,576
|
|
267
|
-
JSON-LD
|
|
268
|
-
mislabeled as invalid JSON. The
|
|
269
|
-
outer bound.
|
|
373
|
+
256 signals of each repeated metadata kind, including each supported social
|
|
374
|
+
property, analyzes at most 64 JSON-LD blocks, and captures at most 1,048,576
|
|
375
|
+
characters from one JSON-LD block. Exceeding a JSON-LD analysis budget produces
|
|
376
|
+
a dedicated warning rather than being mislabeled as invalid JSON. The
|
|
377
|
+
configured response-byte limit remains the outer bound.
|
|
270
378
|
|
|
271
379
|
## Timing interpretation
|
|
272
380
|
|
|
@@ -311,15 +419,18 @@ the maximum.
|
|
|
311
419
|
|
|
312
420
|
Timing spread alone is evidence, not a failure. Network and cache variation can
|
|
313
421
|
change timings without changing the response contract. SSRWire warns when HTTP
|
|
314
|
-
response evidence or streamed metadata changes across samples.
|
|
315
|
-
|
|
316
|
-
|
|
422
|
+
response evidence or streamed metadata changes across samples. Enabled social
|
|
423
|
+
contracts are included in metadata stability; observed social tags remain
|
|
424
|
+
evidence-only when their contracts are disabled. Exact body-hash variation by
|
|
425
|
+
itself is informational because timestamps, nonces, and other legitimate
|
|
426
|
+
dynamic values commonly change source HTML.
|
|
317
427
|
|
|
318
428
|
## CLI reference
|
|
319
429
|
|
|
320
430
|
```text
|
|
321
431
|
ssrwire [urls...] [options]
|
|
322
432
|
ssrwire check [urls...] [options]
|
|
433
|
+
ssrwire compare <baseline.json> <candidate.json> [options]
|
|
323
434
|
ssrwire init [path] [--force]
|
|
324
435
|
```
|
|
325
436
|
|
|
@@ -342,13 +453,27 @@ Check options:
|
|
|
342
453
|
Config-file targets and CLI URLs are combined, with exact duplicate URLs
|
|
343
454
|
removed.
|
|
344
455
|
|
|
456
|
+
Comparison options:
|
|
457
|
+
|
|
458
|
+
| Option | Purpose |
|
|
459
|
+
|---|---|
|
|
460
|
+
| `-f, --format <format>` | `terminal`, `json`, or self-contained `html` |
|
|
461
|
+
| `-o, --output <path>` | Write the comparison to a file |
|
|
462
|
+
| `--fail-on <level>` | `regression` or `never` |
|
|
463
|
+
| `--timing-regression-ms <ms>` | Absolute median slowdown floor; default `250` |
|
|
464
|
+
| `--timing-regression-percent <percent>` | Relative median slowdown floor; default `25` |
|
|
465
|
+
| `--no-color` | Disable terminal color |
|
|
466
|
+
|
|
345
467
|
## Reports and exit codes
|
|
346
468
|
|
|
347
|
-
- `terminal`: compact sample, aggregate-timing, and finding
|
|
469
|
+
- `terminal`: compact sample, social-readiness, aggregate-timing, and finding
|
|
470
|
+
tables for local use.
|
|
348
471
|
- `json`: structured machine-readable evidence, including every probe and timing
|
|
349
472
|
signal plus repeated-run stability summaries.
|
|
350
473
|
- `sarif`: findings suitable for GitHub Code Scanning and other SARIF 2.1.0
|
|
351
474
|
consumers.
|
|
475
|
+
- comparison `html`: a script-free deployment summary and per-agent wire
|
|
476
|
+
waterfall suitable for a CI artifact.
|
|
352
477
|
|
|
353
478
|
Exit codes are stable:
|
|
354
479
|
|
|
@@ -356,7 +481,11 @@ Exit codes are stable:
|
|
|
356
481
|
- `1`: the run completed but crossed the `--fail-on` threshold;
|
|
357
482
|
- `2`: configuration/setup failure or incomplete probe evidence.
|
|
358
483
|
|
|
359
|
-
|
|
484
|
+
For `compare`, exit `1` means at least one regression was introduced under the
|
|
485
|
+
default policy, while invalid or unreadable reports use exit `2`. Neutral
|
|
486
|
+
changes and fixed findings do not fail comparison.
|
|
487
|
+
|
|
488
|
+
`check --fail-on never` suppresses policy failures, but it never converts an
|
|
360
489
|
incomplete probe into a pass.
|
|
361
490
|
|
|
362
491
|
## GitHub Actions
|
|
@@ -414,15 +543,36 @@ const audit = await runAudit(config);
|
|
|
414
543
|
process.stdout.write(renderJson(audit));
|
|
415
544
|
```
|
|
416
545
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
546
|
+
Comparisons use the same primitives as the CLI:
|
|
547
|
+
|
|
548
|
+
```ts
|
|
549
|
+
import { readFile } from "node:fs/promises";
|
|
550
|
+
import {
|
|
551
|
+
compareAudits,
|
|
552
|
+
parseAuditReportText,
|
|
553
|
+
renderComparisonHtml,
|
|
554
|
+
} from "ssrwire";
|
|
555
|
+
|
|
556
|
+
const [baselineJson, candidateJson] = await Promise.all([
|
|
557
|
+
readFile("production.json", "utf8"),
|
|
558
|
+
readFile("preview.json", "utf8"),
|
|
559
|
+
]);
|
|
560
|
+
const baseline = parseAuditReportText(baselineJson, "baseline audit report");
|
|
561
|
+
const candidate = parseAuditReportText(candidateJson, "candidate audit report");
|
|
562
|
+
const comparison = compareAudits(baseline, candidate);
|
|
563
|
+
const html = renderComparisonHtml(comparison);
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
The JSON report's top-level `version` is the SSRWire software version.
|
|
567
|
+
`schemaVersion` separately identifies the persisted report contract used by
|
|
568
|
+
offline comparison.
|
|
420
569
|
|
|
421
570
|
## Scope
|
|
422
571
|
|
|
423
|
-
SSRWire does not execute JavaScript, inspect a hydrated DOM,
|
|
424
|
-
|
|
425
|
-
testing, or emulate a crawler's
|
|
572
|
+
SSRWire does not execute JavaScript, inspect a hydrated DOM, render social
|
|
573
|
+
previews, fetch social images, measure Core Web Vitals, discover URLs, validate
|
|
574
|
+
indexing, bypass access controls, perform load testing, or emulate a crawler's
|
|
575
|
+
rendering pipeline. Use
|
|
426
576
|
[RoutePlay](https://github.com/lame13/routeplay) for server HTML versus a cold
|
|
427
577
|
browser versus real client-side navigation. Use
|
|
428
578
|
[RouteLint](https://github.com/lame13/routelint) for route discovery,
|
package/dist/analyze.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EAEX,OAAO,EACP,WAAW,EAMX,iBAAiB,EAClB,MAAM,YAAY,CAAC;AA2pBpB,wBAAgB,aAAa,CAC3B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC7B,SAAS,OAAO,EAAE,CAwGpB;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GAAG,YAAY,CA6BlF"}
|