vagejs 0.2.0 → 0.3.1
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 +9 -3
- package/dist/checks/crawlability.d.ts +34 -0
- package/dist/checks/crawlability.js +142 -0
- package/dist/checks/verify.d.ts +8 -1
- package/dist/checks/verify.js +108 -11
- package/dist/cli/index.js +6 -4
- package/dist/cli/info.d.ts +11 -0
- package/dist/cli/info.js +20 -5
- package/dist/content/images.d.ts +4 -1
- package/dist/content/images.js +36 -3
- package/dist/content/markdown.d.ts +2 -0
- package/dist/content/markdown.js +2 -0
- package/dist/content/optimize.d.ts +31 -0
- package/dist/content/optimize.js +92 -0
- package/dist/content/sanitize.d.ts +8 -1
- package/dist/content/sanitize.js +3 -3
- package/dist/core/build.js +11 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +24 -2
- package/dist/core/dates.d.ts +2 -0
- package/dist/core/dates.js +4 -0
- package/dist/core/pages.d.ts +28 -1
- package/dist/core/pages.js +86 -11
- package/dist/core/render.d.ts +7 -0
- package/dist/core/render.js +19 -2
- package/dist/core/site.js +50 -9
- package/dist/deploy/github-pages.js +2 -0
- package/dist/deploy/headers.d.ts +13 -2
- package/dist/deploy/headers.js +15 -3
- package/dist/dev/guard.d.ts +2 -0
- package/dist/dev/guard.js +30 -1
- package/dist/dev/server.js +19 -3
- package/dist/discovery/feed.d.ts +21 -0
- package/dist/discovery/feed.js +68 -0
- package/dist/discovery/git-dates.d.ts +10 -0
- package/dist/discovery/git-dates.js +57 -0
- package/dist/discovery/markdown-copy.d.ts +23 -0
- package/dist/discovery/markdown-copy.js +152 -0
- package/dist/guidelines/rule-pack.json +133 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/seo/head.js +16 -0
- package/package.json +4 -1
- package/templates/starter/.github/workflows/ci.yml +2 -0
- package/templates/starter/.github/workflows/verify.yml +2 -0
- package/templates/starter/AGENTS.md +15 -7
- package/templates/starter/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2026.10.
|
|
3
|
-
"released": "2026-10-
|
|
2
|
+
"version": "2026.10.2",
|
|
3
|
+
"released": "2026-10-24",
|
|
4
4
|
"sources": [
|
|
5
5
|
{
|
|
6
6
|
"id": "google-search-essentials",
|
|
@@ -266,6 +266,22 @@
|
|
|
266
266
|
"url": "https://developers.cloudflare.com/pages/configuration/headers/",
|
|
267
267
|
"category": "hosting",
|
|
268
268
|
"cadence": "weekly"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"id": "perplexity-bots",
|
|
272
|
+
"provider": "Perplexity",
|
|
273
|
+
"title": "Perplexity Crawlers",
|
|
274
|
+
"url": "https://docs.perplexity.ai/guides/bots",
|
|
275
|
+
"category": "ai-crawlers",
|
|
276
|
+
"cadence": "weekly"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "apple-applebot",
|
|
280
|
+
"provider": "Apple",
|
|
281
|
+
"title": "About Applebot (incl. Applebot-Extended)",
|
|
282
|
+
"url": "https://support.apple.com/en-us/119829",
|
|
283
|
+
"category": "ai-crawlers",
|
|
284
|
+
"cadence": "weekly"
|
|
269
285
|
}
|
|
270
286
|
],
|
|
271
287
|
"rules": [
|
|
@@ -276,7 +292,9 @@
|
|
|
276
292
|
"sources": [
|
|
277
293
|
"openai-bots",
|
|
278
294
|
"anthropic-crawlers",
|
|
279
|
-
"google-crawlers"
|
|
295
|
+
"google-crawlers",
|
|
296
|
+
"perplexity-bots",
|
|
297
|
+
"apple-applebot"
|
|
280
298
|
],
|
|
281
299
|
"implementedIn": [
|
|
282
300
|
"src/discovery/crawlers.ts",
|
|
@@ -313,6 +331,18 @@
|
|
|
313
331
|
"provider": "Google",
|
|
314
332
|
"purpose": "training",
|
|
315
333
|
"source": "google-crawlers"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"token": "PerplexityBot",
|
|
337
|
+
"provider": "Perplexity",
|
|
338
|
+
"purpose": "search",
|
|
339
|
+
"source": "perplexity-bots"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"token": "Applebot-Extended",
|
|
343
|
+
"provider": "Apple",
|
|
344
|
+
"purpose": "training",
|
|
345
|
+
"source": "apple-applebot"
|
|
316
346
|
}
|
|
317
347
|
]
|
|
318
348
|
}
|
|
@@ -595,7 +625,92 @@
|
|
|
595
625
|
"src/deploy/headers.ts"
|
|
596
626
|
],
|
|
597
627
|
"data": {
|
|
598
|
-
"maxLineLength": 2000
|
|
628
|
+
"maxLineLength": 2000,
|
|
629
|
+
"maxRules": 100
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"id": "crawlers.probes",
|
|
634
|
+
"summary": "Crawlers `vage verify` impersonates to test that a live site lets search and AI crawlers in. Full user-agent strings only where we could copy them verbatim from the provider's page (W.X.Y.Z = current Chrome version); otherwise the documented token, which is what CDN bot rules match. A user-agent probe can't detect blocks based on the real crawlers' IP addresses.",
|
|
635
|
+
"behaviorChanging": true,
|
|
636
|
+
"sources": [
|
|
637
|
+
"google-crawlers",
|
|
638
|
+
"bing-guidelines",
|
|
639
|
+
"openai-bots",
|
|
640
|
+
"anthropic-crawlers",
|
|
641
|
+
"perplexity-bots"
|
|
642
|
+
],
|
|
643
|
+
"implementedIn": [
|
|
644
|
+
"src/checks/crawlability.ts"
|
|
645
|
+
],
|
|
646
|
+
"data": {
|
|
647
|
+
"crawlers": [
|
|
648
|
+
{
|
|
649
|
+
"token": "Googlebot",
|
|
650
|
+
"provider": "Google",
|
|
651
|
+
"purpose": "search",
|
|
652
|
+
"userAgent": "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/W.X.Y.Z Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
|
|
653
|
+
"source": "google-crawlers"
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
"token": "bingbot",
|
|
657
|
+
"provider": "Microsoft",
|
|
658
|
+
"purpose": "search",
|
|
659
|
+
"source": "bing-guidelines"
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
"token": "OAI-SearchBot",
|
|
663
|
+
"provider": "OpenAI",
|
|
664
|
+
"purpose": "ai-search",
|
|
665
|
+
"source": "openai-bots"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"token": "GPTBot",
|
|
669
|
+
"provider": "OpenAI",
|
|
670
|
+
"purpose": "ai-training",
|
|
671
|
+
"userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot",
|
|
672
|
+
"source": "openai-bots"
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"token": "ChatGPT-User",
|
|
676
|
+
"provider": "OpenAI",
|
|
677
|
+
"purpose": "ai-user",
|
|
678
|
+
"userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot",
|
|
679
|
+
"source": "openai-bots"
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"token": "Claude-SearchBot",
|
|
683
|
+
"provider": "Anthropic",
|
|
684
|
+
"purpose": "ai-search",
|
|
685
|
+
"source": "anthropic-crawlers"
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
"token": "ClaudeBot",
|
|
689
|
+
"provider": "Anthropic",
|
|
690
|
+
"purpose": "ai-training",
|
|
691
|
+
"source": "anthropic-crawlers"
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"token": "Claude-User",
|
|
695
|
+
"provider": "Anthropic",
|
|
696
|
+
"purpose": "ai-user",
|
|
697
|
+
"source": "anthropic-crawlers"
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
"token": "PerplexityBot",
|
|
701
|
+
"provider": "Perplexity",
|
|
702
|
+
"purpose": "ai-search",
|
|
703
|
+
"userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)",
|
|
704
|
+
"source": "perplexity-bots"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
"token": "Perplexity-User",
|
|
708
|
+
"provider": "Perplexity",
|
|
709
|
+
"purpose": "ai-user",
|
|
710
|
+
"userAgent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)",
|
|
711
|
+
"source": "perplexity-bots"
|
|
712
|
+
}
|
|
713
|
+
]
|
|
599
714
|
}
|
|
600
715
|
}
|
|
601
716
|
],
|
|
@@ -606,6 +721,20 @@
|
|
|
606
721
|
"summary": "Initial rule pack (unreleased; extended during Phase 8 and the security review with IndexNow, Clarity, Plausible, Cloudflare Pages and CSP provider rules). Facts checked against the cited sources on 2026-10-23 during implementation.",
|
|
607
722
|
"reviewedBy": "Venkatesh A G E",
|
|
608
723
|
"contentHash": "8c7272511f733c01984ce1d962b39e2d521a88b31a5c958a95307a04b82bb3dd"
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
"version": "2026.10.1",
|
|
727
|
+
"date": "2026-10-23",
|
|
728
|
+
"summary": "Add crawlers.probes (search and AI crawler user agents and tokens for vage verify's crawlability check) and the Perplexity crawler source. Full user-agent strings copied verbatim on 2026-10-23 for Googlebot, GPTBot, ChatGPT-User, PerplexityBot and Perplexity-User; OAI-SearchBot, Anthropic's crawlers and bingbot are recorded by token (Anthropic's page lists only tokens, Bing's page couldn't be read, and OAI-SearchBot's full string couldn't be copied verbatim). No existing rule changed.",
|
|
729
|
+
"reviewedBy": "Venkatesh A G E",
|
|
730
|
+
"contentHash": "4d88418eb0b5425da970a1a30218a097783e117ce65376171d9a7f3ab7d9f658"
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
"version": "2026.10.2",
|
|
734
|
+
"date": "2026-10-24",
|
|
735
|
+
"summary": "robots.ai-crawlers: add PerplexityBot (search; Perplexity says it surfaces and links sites in its search results and is not used for foundation-model training) and Applebot-Extended (training; Apple says it does not crawl and only controls use of Applebot-crawled data for training its generative models). Google-Extended stays under training; its source also covers grounding in Gemini Apps and Vertex AI, which the docs now state. Perplexity-User is excluded as a user-initiated fetcher. CCBot and cohere-ai not added: no provider documentation describing them as AI-training robots.txt tokens was found. Checked against the cited sources on 2026-10-24. cloudflare.headers: record the documented limit of 100 rules as data (maxRules), used to add a canonical Link header to each Markdown copy only when the _headers file stays within it.",
|
|
736
|
+
"reviewedBy": "Venkatesh A G E",
|
|
737
|
+
"contentHash": "6b1d977ca79843dab0f6b03dc8b3448ca451eafb037bc6af112165fb5c1035c1"
|
|
609
738
|
}
|
|
610
739
|
]
|
|
611
740
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { escapeHtml, html, raw, type SafeHtml } from "./core/html.js";
|
|
|
4
4
|
export { z } from "zod";
|
|
5
5
|
export type { Layout, LayoutProps } from "./core/render.js";
|
|
6
6
|
export type { Frontmatter } from "./content/markdown.js";
|
|
7
|
-
export { collection, type CollectionOptions, type PageSummary } from "./core/pages.js";
|
|
7
|
+
export { breadcrumbs, collection, flatten, neighbors, tree, type CollectionOptions, type PageSummary, type TreeNode } from "./core/pages.js";
|
|
8
8
|
export { build, type BuildResult } from "./core/build.js";
|
|
9
9
|
export { startDevServer } from "./dev/server.js";
|
|
10
10
|
export { startPreviewServer } from "./dev/preview.js";
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export { defineConfig } from "./core/config.js";
|
|
|
2
2
|
export { escapeHtml, html, raw } from "./core/html.js";
|
|
3
3
|
/** Zod, for layout field schemas: `export const frontmatter = z.object({ ... })`. Same instance vagejs validates with. */
|
|
4
4
|
export { z } from "zod";
|
|
5
|
-
export { collection } from "./core/pages.js";
|
|
5
|
+
export { breadcrumbs, collection, flatten, neighbors, tree } from "./core/pages.js";
|
|
6
6
|
export { build } from "./core/build.js";
|
|
7
7
|
export { startDevServer } from "./dev/server.js";
|
|
8
8
|
export { startPreviewServer } from "./dev/preview.js";
|
package/dist/seo/head.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VageError } from "../core/errors.js";
|
|
2
2
|
import { escapeHtml } from "../core/html.js";
|
|
3
|
+
import { feedTitle } from "../discovery/feed.js";
|
|
3
4
|
import { article, jsonLdScript, organization, website } from "./jsonld.js";
|
|
4
5
|
import { absoluteUrl } from "./urls.js";
|
|
5
6
|
export function pageMeta(site, route, frontmatter, notFound = false) {
|
|
@@ -38,6 +39,21 @@ export function headTags(site, m) {
|
|
|
38
39
|
if (image)
|
|
39
40
|
tags.push(meta("property", "og:image", image));
|
|
40
41
|
tags.push(meta("name", "twitter:card", image ? "summary_large_image" : "summary"));
|
|
42
|
+
// Markdown copy for AI tools (seo.markdownCopies), on pages that are listed.
|
|
43
|
+
if (site.seo.markdownCopies && m.canonical && m.canonical === absoluteUrl(site.site, m.route)) {
|
|
44
|
+
const href = m.route === "/" ? "/index.md" : `${m.route.slice(0, -1)}.md`;
|
|
45
|
+
tags.push({ exists: /<link[^>]+text\/markdown/i, html: `<link rel="alternate" type="text/markdown" href="${escapeHtml(href)}" />` });
|
|
46
|
+
}
|
|
47
|
+
// Feed discovery: pages in a section with a feed point readers to it.
|
|
48
|
+
for (const feed of site.site ? site.seo.feeds : []) {
|
|
49
|
+
if (!m.route.startsWith(feed.under))
|
|
50
|
+
continue;
|
|
51
|
+
const href = `${site.site}${feed.under}feed.xml`;
|
|
52
|
+
tags.push({
|
|
53
|
+
exists: /<link[^>]+application\/rss\+xml/i,
|
|
54
|
+
html: `<link rel="alternate" type="application/rss+xml" title="${escapeHtml(feedTitle(site, feed))}" href="${escapeHtml(href)}" />`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
41
57
|
const schemas = structuredData(site, m, description, image);
|
|
42
58
|
if (schemas.length) {
|
|
43
59
|
tags.push({ exists: /<script[^>]+application\/ld\+json/i, html: jsonLdScript(schemas.length === 1 ? schemas[0] : schemas) });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vagejs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "AI-native, static-first web framework: Markdown sites with built-in SEO, llms.txt, audits, security and safe deploys.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static-site-generator",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"jsdom": "^28.1.0",
|
|
51
51
|
"marked": "^18.1.1",
|
|
52
52
|
"node-html-parser": "^9.0.5",
|
|
53
|
+
"turndown": "^7.2.4",
|
|
53
54
|
"vite": "^8.3.5",
|
|
54
55
|
"yaml": "^2.9.1",
|
|
55
56
|
"zod": "^4.6.7"
|
|
@@ -58,7 +59,9 @@
|
|
|
58
59
|
"@anthropic-ai/sdk": "^1.1.0",
|
|
59
60
|
"@types/jsdom": "^28.0.3",
|
|
60
61
|
"@types/node": "^26.6.5",
|
|
62
|
+
"@types/turndown": "^5.0.6",
|
|
61
63
|
"lighthouse": "^13.5.0",
|
|
64
|
+
"sharp": "^0.35.5",
|
|
62
65
|
"typescript": "^7.0.2",
|
|
63
66
|
"vitest": "^5.0.5"
|
|
64
67
|
},
|
|
@@ -26,7 +26,10 @@ Run `npm run check` after every change and fix all errors before finishing.
|
|
|
26
26
|
- **Add a layout:** `src/layouts/<name>.ts`, then `layout: <name>` in frontmatter. Keep `<html lang>`, one `<title>` and `</head>`.
|
|
27
27
|
- **List pages (blog index, "latest posts", a sidebar):** in a layout, `collection(pages, { under: "/blog/", sort: "date" })` from `vagejs`. Never keep a hand-written list of pages.
|
|
28
28
|
- **Give a layout its own frontmatter fields:** `export const frontmatter = z.object({ ... })` in the layout (`import { z } from "vagejs"`). Pages using it are then checked strictly: unknown or mistyped fields fail the build.
|
|
29
|
-
- **Add an image:** put it in `public/images/` and write ``. Width and height are filled in from the file; write real alt text.
|
|
29
|
+
- **Add an image:** put it in `public/images/` and write ``. Width and height are filled in from the file; write real alt text. For resized WebP copies, the owner can turn on `images: { optimize: true }` (needs `npm install --save-dev sharp`). Only images in page content are optimized, not images a layout writes.
|
|
30
|
+
- **Order a menu or sidebar:** set `order:` (lower first) and optionally a short `navTitle:` in each page's frontmatter (shown as `p.label`), then build the menu in a layout with `tree(pages, "/docs/")`. For previous/next links in the same order use `neighbors(flatten(tree(pages, "/docs/")), page.route)`. For a flat section, `collection(pages, { under: "/docs/", sort: "order", includeIndex: true })` works too. `breadcrumbs(pages, page.route)` gives the trail from the home page.
|
|
31
|
+
- **Add an RSS feed for the blog:** `seo: { feeds: [{ under: "/blog/" }] }` in `vage.config.ts` writes `/blog/feed.xml`, newest `datePublished` first (undated posts last, without a date).
|
|
32
|
+
- **Help AI tools read the site:** `seo: { markdownCopies: true }` publishes a Markdown copy of every listed page (`/docs/cli/` becomes `/docs/cli.md`), converted from the page's `<main>`, so it contains exactly what the page shows (including content a layout builds from frontmatter), and `llms.txt` links to them. In layouts, add `data-vage-copy="skip"` to repeated extras such as share links or a call to action to leave them out of the copy. On Cloudflare, each copy gets a canonical `Link` header pointing to its page. `seo: { lastmod: "git" }` dates the sitemap from git history (needs full history in CI: `fetch-depth: 0`).
|
|
30
33
|
- **Rename a page:** move the file, then add `redirects: { "/old-slug/": "/new-slug/" }` to `vage.config.ts`.
|
|
31
34
|
- **Hide a page from search:** `noindex: true` (it stays published). To unpublish, use `draft: true` or delete it.
|
|
32
35
|
- **AI crawler policy:** set `seo.robots.aiTraining` / `aiSearch` only on the owner's instruction.
|
|
@@ -61,7 +64,9 @@ image: /images/og.png # og:image (made absolute using `site`)
|
|
|
61
64
|
type: article # og:type + Article JSON-LD (default: website)
|
|
62
65
|
author: Jane Doe # Article author
|
|
63
66
|
datePublished: 2026-01-31
|
|
64
|
-
dateModified: 2026-02-15 # also
|
|
67
|
+
dateModified: 2026-02-15 # also the sitemap <lastmod> (otherwise datePublished, or git with seo.lastmod: "git")
|
|
68
|
+
order: 2 # position in menus built with tree() or sort: "order" (lower first)
|
|
69
|
+
navTitle: Pricing # shorter label for menus and breadcrumbs (PageSummary.label)
|
|
65
70
|
---
|
|
66
71
|
```
|
|
67
72
|
|
|
@@ -75,7 +80,7 @@ Hacked sites are usually abused for hidden spam links and doorway pages. vagejs
|
|
|
75
80
|
- **`links.lock.json` lists the external domains the site may link to.** A link to any other domain fails `npm run check` (`link-unapproved`). Only the owner approves domains: show them `npx vage links` and let them run `npx vage links approve <domain>`. Never run `approve` with `--yes` or `--all` yourself unless the owner told you to in this conversation.
|
|
76
81
|
- Inline `style="..."` is removed from page content (`markdown.inlineStyles` is off), and `vage check` fails on links hidden with CSS (`link-hidden`). Style pages in layouts.
|
|
77
82
|
- `vage check` warns about common spam words (`spam-pattern`). Report them to the owner; don't delete or reword content you didn't write without asking.
|
|
78
|
-
- `npx vage verify` compares the live site with these files and fails on links, scripts or pages that aren't in the repository. `.github/workflows/verify.yml` runs it daily once the owner sets the `VAGE_VERIFY_URL` repository variable.
|
|
83
|
+
- `npx vage verify` compares the live site with these files and fails on links, scripts or pages that aren't in the repository. It also checks that search and AI crawlers can reach the site, that `http` and `www` addresses redirect, and warns about scripts the host or CDN injects. `.github/workflows/verify.yml` runs it daily once the owner sets the `VAGE_VERIFY_URL` repository variable.
|
|
79
84
|
- CI runs `npm audit`, and `.github/dependabot.yml` proposes dependency updates. Review them like any other change.
|
|
80
85
|
|
|
81
86
|
## Content safety
|
|
@@ -107,13 +112,16 @@ From the published pages and config (never from `public/`; a hand-written `publi
|
|
|
107
112
|
- `sitemap.xml`: indexable, self-canonical, non-draft pages. Needs `site`.
|
|
108
113
|
- `llms.txt` (+ `llms-full.txt` with `llmsTxt: { full: true }`): same pages. An emerging convention; not a guarantee that AI tools use it.
|
|
109
114
|
- Redirects: `redirects: { "/old/": "/new/" }` become noindex meta-refresh pages (dev server answers 301).
|
|
115
|
+
- With `seo.feeds`: `<section>/feed.xml` (RSS). With `seo.markdownCopies`: `/<path>.md` copies of listed pages. With `images.optimize`: resized images in `/_vage/img/`.
|
|
116
|
+
|
|
110
117
|
|
|
111
118
|
## Config
|
|
112
119
|
|
|
113
120
|
`vage.config.ts` keys: `site` (origin only, no path), `title`, `description`, `lang`,
|
|
114
|
-
`seo: { robots, sitemap, llmsTxt, structuredData }`, `redirects`, `markdown`,
|
|
115
|
-
`
|
|
116
|
-
`
|
|
121
|
+
`seo: { robots, sitemap, llmsTxt, structuredData, feeds, markdownCopies, lastmod }`, `redirects`, `markdown`,
|
|
122
|
+
`images: { optimize, widths, quality, sizes }`, `performance`, `deploy: { target, cloudflareWorker, cloudflareProject }`,
|
|
123
|
+
`security: { headers, csp, cspSources, outboundLinks, spamPatterns }`, `integrations`, `guidelines`.
|
|
124
|
+
Keys not in this list are an error; `npx vage info --json` has the full schema.
|
|
117
125
|
|
|
118
126
|
## Performance and accessibility
|
|
119
127
|
|
|
@@ -155,7 +163,7 @@ Off unless configured in `vage.config.ts` under `integrations`. Ask the site own
|
|
|
155
163
|
|
|
156
164
|
## Not implemented yet
|
|
157
165
|
|
|
158
|
-
Bing Webmaster Tools API, Netlify/Vercel adapters, CMS content sources, multi-language sites, base paths,
|
|
166
|
+
Bing Webmaster Tools API, Netlify/Vercel adapters, CMS content sources, multi-language sites, base paths, AVIF images. Do not use or document them as available. A passing `check` does not guarantee indexing, rankings or AI citations.
|
|
159
167
|
|
|
160
168
|
## Favicon
|
|
161
169
|
|