vagejs 0.2.0 → 0.3.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.
Files changed (45) hide show
  1. package/README.md +9 -3
  2. package/dist/checks/crawlability.d.ts +34 -0
  3. package/dist/checks/crawlability.js +142 -0
  4. package/dist/checks/verify.d.ts +8 -1
  5. package/dist/checks/verify.js +108 -11
  6. package/dist/cli/index.js +6 -4
  7. package/dist/cli/info.d.ts +11 -0
  8. package/dist/cli/info.js +20 -5
  9. package/dist/content/images.d.ts +4 -1
  10. package/dist/content/images.js +36 -3
  11. package/dist/content/markdown.d.ts +2 -0
  12. package/dist/content/markdown.js +2 -0
  13. package/dist/content/optimize.d.ts +31 -0
  14. package/dist/content/optimize.js +92 -0
  15. package/dist/content/sanitize.d.ts +8 -1
  16. package/dist/content/sanitize.js +3 -3
  17. package/dist/core/build.js +11 -0
  18. package/dist/core/config.d.ts +17 -0
  19. package/dist/core/config.js +22 -0
  20. package/dist/core/dates.d.ts +2 -0
  21. package/dist/core/dates.js +4 -0
  22. package/dist/core/pages.d.ts +28 -1
  23. package/dist/core/pages.js +86 -11
  24. package/dist/core/render.d.ts +7 -0
  25. package/dist/core/render.js +19 -2
  26. package/dist/core/site.js +43 -7
  27. package/dist/deploy/github-pages.js +2 -0
  28. package/dist/dev/guard.d.ts +2 -0
  29. package/dist/dev/guard.js +30 -1
  30. package/dist/dev/server.js +19 -3
  31. package/dist/discovery/feed.d.ts +21 -0
  32. package/dist/discovery/feed.js +68 -0
  33. package/dist/discovery/git-dates.d.ts +10 -0
  34. package/dist/discovery/git-dates.js +57 -0
  35. package/dist/discovery/markdown-copy.d.ts +13 -0
  36. package/dist/discovery/markdown-copy.js +112 -0
  37. package/dist/guidelines/rule-pack.json +100 -1
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/seo/head.js +16 -0
  41. package/package.json +4 -1
  42. package/templates/starter/.github/workflows/ci.yml +2 -0
  43. package/templates/starter/.github/workflows/verify.yml +2 -0
  44. package/templates/starter/AGENTS.md +15 -7
  45. package/templates/starter/package.json +1 -1
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.2.0",
3
+ "version": "0.3.0",
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
  },
@@ -12,6 +12,8 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - uses: actions/checkout@v7
15
+ with:
16
+ fetch-depth: 0 # full history, so seo.lastmod: "git" can date pages
15
17
  - uses: actions/setup-node@v7
16
18
  with:
17
19
  node-version: 22
@@ -19,6 +19,8 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
21
  - uses: actions/checkout@v7
22
+ with:
23
+ fetch-depth: 0 # full history, so seo.lastmod: "git" can date pages
22
24
  - uses: actions/setup-node@v7
23
25
  with:
24
26
  node-version: 22
@@ -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 `![Describe the image](/images/name.jpg)`. Width and height are filled in from the file; write real alt text.
29
+ - **Add an image:** put it in `public/images/` and write `![Describe the image](/images/name.jpg)`. 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 published HTML page, so it contains exactly what the page shows, and `llms.txt` links to them. `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 used as sitemap <lastmod>
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`, `performance`,
115
- `deploy: { target, cloudflareWorker, cloudflareProject }`, `security: { headers, csp, cspSources }`,
116
- `integrations`, `guidelines`. Unknown keys are an error; `npx vage info --json` has the full schema.
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, image resizing and WebP/AVIF conversion. Do not use or document them as available. A passing `check` does not guarantee indexing, rankings or AI citations.
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
 
@@ -11,6 +11,6 @@
11
11
  "preview": "vage preview"
12
12
  },
13
13
  "devDependencies": {
14
- "vagejs": "^0.2.0"
14
+ "vagejs": "^0.3.0"
15
15
  }
16
16
  }