pagegraph 0.5.0 → 0.6.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 +80 -4
- package/dist/audit.d.ts +8 -3
- package/dist/audit.js +1931 -1
- package/dist/audit.js.map +1 -0
- package/dist/{graph-BlLoEOw2.d.ts → checks-BfsQtKga.d.ts} +43 -2
- package/dist/cli.js +41973 -35
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +7 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +131 -14
- package/dist/index.js +618 -2
- package/dist/index.js.map +1 -1
- package/dist/links-sGbLkl-7.js +184 -0
- package/dist/links-sGbLkl-7.js.map +1 -0
- package/package.json +13 -8
- package/dist/audit-B96V1x3q.js +0 -1929
- package/dist/audit-B96V1x3q.js.map +0 -1
- package/dist/inspect-html-CHuoiO2s.js +0 -452
- package/dist/inspect-html-CHuoiO2s.js.map +0 -1
- package/dist/main-GFEobQTH.js +0 -750
- package/dist/main-GFEobQTH.js.map +0 -1
package/README.md
CHANGED
|
@@ -22,8 +22,7 @@ flowchart LR
|
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
bun add pagegraph
|
|
25
|
-
bun add -D
|
|
26
|
-
bun add -D lighthouse # only for `pagegraph audit` performance evidence
|
|
25
|
+
bun add -D lighthouse # only for `pagegraph audit` performance evidence
|
|
27
26
|
```
|
|
28
27
|
|
|
29
28
|
| Entry | Exports | Peers |
|
|
@@ -33,11 +32,16 @@ bun add -D lighthouse # only for `pagegraph audit` performanc
|
|
|
33
32
|
| `pagegraph/vite` | `seoRouteConfig` coverage gate | `vite` |
|
|
34
33
|
| `pagegraph/config` | `defineSeoConfig`, `viteGraphLoader` | `vite` |
|
|
35
34
|
| `pagegraph/audit` | Audit services, scanner protocol, rules, and report schemas | `effect` |
|
|
36
|
-
| `pagegraph` bin
|
|
35
|
+
| `pagegraph` bin | CLI over the same graph | bundled — runs on Bun |
|
|
37
36
|
|
|
38
37
|
The core and React entries have **zero runtime dependencies** — everything above is a
|
|
39
38
|
peer, and only the entries you import need theirs installed.
|
|
40
39
|
|
|
40
|
+
The CLI **bundles Effect and the TypeSafe provider**, so it needs no Effect peers and does not
|
|
41
|
+
depend on the app's Effect RC; it runs on [Bun](https://bun.sh) (`bunx pagegraph`). `vite` stays a
|
|
42
|
+
peer — the graph commands load your app through Vite at runtime — and `lighthouse` is only needed by
|
|
43
|
+
`pagegraph audit`. Importing `pagegraph/audit` programmatically still needs `effect`.
|
|
44
|
+
|
|
41
45
|
## Quick start
|
|
42
46
|
|
|
43
47
|
**1. Bind your site identity once.** Route files never see an origin or a brand name.
|
|
@@ -245,7 +249,7 @@ severities:
|
|
|
245
249
|
- **structural** — internally broken declarations; these fail `pagegraph check` (exit 1):
|
|
246
250
|
dead or duplicate edges, path collisions, a redirect in the sitemap, a
|
|
247
251
|
sitemap/noindex contradiction, a `related` target with no `link` card, an
|
|
248
|
-
instance without a title.
|
|
252
|
+
instance without a title, or an unmet contextual-link coverage rule.
|
|
249
253
|
- **editorial** — quality smells, reported but non-failing: duplicate or mis-sized
|
|
250
254
|
titles and descriptions.
|
|
251
255
|
|
|
@@ -285,6 +289,8 @@ export default defineSeoConfig({
|
|
|
285
289
|
origin: "https://example.com",
|
|
286
290
|
disallow: routeConfig.robotsExclusions,
|
|
287
291
|
contentSignal: "search=yes, ai-input=yes, ai-train=yes",
|
|
292
|
+
// Fail `check` unless each named money page has enough contextual links.
|
|
293
|
+
coverage: [{ path: "/pricing", minInbound: 2 }, { path: "/features/*", minInbound: 1 }],
|
|
288
294
|
loadGraph: viteGraphLoader({
|
|
289
295
|
root: import.meta.dirname,
|
|
290
296
|
entry: "/lib/seo/graph.ts",
|
|
@@ -298,12 +304,82 @@ pagegraph check # CI gate — exit 1 on structural violations
|
|
|
298
304
|
pagegraph graph # the graph as a tree · --format mermaid | json
|
|
299
305
|
pagegraph inspect /pricing # one node: policy, sitemap status, in/out edges
|
|
300
306
|
pagegraph inspect <url> --live # fetch a deployed page, validate its rendered <head>
|
|
307
|
+
pagegraph links verify <url> # crawl served HTML: depth, orphans, declared-vs-rendered
|
|
308
|
+
pagegraph links candidates # propose contextual links from the declared graph
|
|
309
|
+
pagegraph links decide <file> # answer typed link questions with Jev (TYPESAFE_API_KEY)
|
|
301
310
|
pagegraph sitemap # print sitemap.xml
|
|
302
311
|
pagegraph robots # print robots.txt
|
|
303
312
|
```
|
|
304
313
|
|
|
305
314
|
Stdout is data, stderr is status — `pagegraph check --json | jq` just works.
|
|
306
315
|
|
|
316
|
+
### Verify the rendered link graph
|
|
317
|
+
|
|
318
|
+
`pagegraph links verify` crawls a site's served HTML — through the same DNS-pinned,
|
|
319
|
+
private-IP-blocked HTTP path as `pagegraph audit` — and reports what a crawler
|
|
320
|
+
actually receives: the real homepage depth, the pages with no incoming internal
|
|
321
|
+
edge (rendered orphans), and, when the app has a `seo.config.ts`, the
|
|
322
|
+
declared-vs-rendered link diff. It is bounded with `--limit` and needs no
|
|
323
|
+
framework or config:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
pagegraph links verify https://example.com
|
|
327
|
+
pagegraph links verify https://example.com --limit 25 --json | jq
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Propose contextual links
|
|
331
|
+
|
|
332
|
+
`pagegraph links candidates` reads the declared graph and proposes
|
|
333
|
+
`(source, destination)` pairs that are plausible contextual links and not already
|
|
334
|
+
connected. Pages are grouped into clusters — a shared top-level section, or the
|
|
335
|
+
same `kind` for root-level pages — and only sitemap-eligible pages are proposed.
|
|
336
|
+
Pairs already declared as a `related` edge are excluded, and `--rendered` accepts
|
|
337
|
+
a JSON dump of already-served anchors (`[{ from, to }]` or `{ edges: [...] }`) to
|
|
338
|
+
exclude those too.
|
|
339
|
+
|
|
340
|
+
The output is a reviewable plan: human text by default, versioned JSON with
|
|
341
|
+
`--json`. Nothing is applied. `--limit` and `--cluster` bound the plan, and
|
|
342
|
+
`--decide` optionally hands the candidates to Jev for a recommendation and
|
|
343
|
+
confidence per pair (requires `TYPESAFE_API_KEY`):
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
pagegraph links candidates
|
|
347
|
+
pagegraph links candidates --cluster blog --limit 20
|
|
348
|
+
pagegraph links candidates --rendered rendered.json --json | jq
|
|
349
|
+
pagegraph links candidates --decide
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Decide with Jev
|
|
353
|
+
|
|
354
|
+
`pagegraph links decide` answers two typed questions per candidate — *does the source have a genuine
|
|
355
|
+
reason to link to the destination?* and *is descriptive anchor text already in the copy?* — and
|
|
356
|
+
routes anything inside the confidence band `(1−t, t)` to a `review` bucket instead of auto-applying.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
pagegraph links decide candidates.json --threshold 0.9
|
|
360
|
+
pagegraph links decide candidates.json --threshold 0.9 --json | jq
|
|
361
|
+
cat candidates.json | pagegraph links decide
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Decisions run through [Jev](https://typesafe.ai) via `@effect/ai-typesafe` (model `jev-latest`),
|
|
365
|
+
bundled into the CLI. The API key is read from the **`TYPESAFE_API_KEY` environment variable** — it
|
|
366
|
+
is deliberately not a `seo.config.ts` field, so keys never live in the repo; `seo.config.ts` carries
|
|
367
|
+
non-secret decision settings only. Without a key the command exits 1 with a clear message and an
|
|
368
|
+
empty stdout.
|
|
369
|
+
|
|
370
|
+
### Contextual-link coverage
|
|
371
|
+
|
|
372
|
+
Declare a contextual-link coverage policy in `seo.config.ts` (a `coverage` array
|
|
373
|
+
of `{ path, minInbound }`), or pass repeatable `--require-inbound "<path-glob>=<n>"`
|
|
374
|
+
flags to override it for one run. `pagegraph check` then fails (exit 1) unless
|
|
375
|
+
every sitemap-eligible page matching the glob has at least `minInbound` incoming
|
|
376
|
+
`related` edges. `*` matches within a path segment and `**` crosses segments; a
|
|
377
|
+
rule that matches no sitemap-eligible page is itself a violation.
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
pagegraph check --require-inbound "/pricing=2" --require-inbound "/features/*=1"
|
|
381
|
+
```
|
|
382
|
+
|
|
307
383
|
### Audit any website
|
|
308
384
|
|
|
309
385
|
`pagegraph audit` is framework-independent and does not need `seo.config.ts`. It
|
package/dist/audit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Layer from "effect/Layer";
|
|
4
4
|
import { Data, Schema } from "effect";
|
|
5
5
|
import "node:net";
|
|
@@ -98,6 +98,11 @@ interface ProbeOptions {
|
|
|
98
98
|
readonly timeoutMs: number;
|
|
99
99
|
readonly maxBodyBytes: number;
|
|
100
100
|
readonly allowPrivate: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Capture resolved anchors from HTML bodies. Opt-in because it is the only
|
|
103
|
+
* probe field that grows with document size; the audit report leaves it unset.
|
|
104
|
+
*/
|
|
105
|
+
readonly captureAnchors?: boolean | undefined;
|
|
101
106
|
}
|
|
102
107
|
interface AuditOptions {
|
|
103
108
|
readonly concurrency?: number;
|
|
@@ -179,7 +184,7 @@ interface Scanner {
|
|
|
179
184
|
readonly id: ScannerId;
|
|
180
185
|
readonly description?: string;
|
|
181
186
|
readonly rules?: readonly ScannerRule[];
|
|
182
|
-
readonly scan: (input: ScannerInput) => Effect
|
|
187
|
+
readonly scan: (input: ScannerInput) => Effect.Effect<ScannerObservation, ScannerFailure>;
|
|
183
188
|
}
|
|
184
189
|
declare const scanner: (definition: Scanner) => Scanner;
|
|
185
190
|
//#endregion
|
|
@@ -213,7 +218,7 @@ interface AuditRequest {
|
|
|
213
218
|
readonly scanners?: readonly string[];
|
|
214
219
|
}
|
|
215
220
|
interface AuditService {
|
|
216
|
-
readonly run: (request: AuditRequest) => Effect
|
|
221
|
+
readonly run: (request: AuditRequest) => Effect.Effect<AuditReport, AuditError>;
|
|
217
222
|
}
|
|
218
223
|
declare namespace Audit {
|
|
219
224
|
const Service_base: Context.ServiceClass<Service, "pagegraph/Audit", AuditService>;
|