{
  "schema": "leumas.docs.page/1",
  "id": "adapter:domain/seo",
  "slug": "adapters/domain/seo",
  "kind": "capabilities",
  "bucket": "package",
  "title": "seo adapter pack",
  "name": "seo adapter pack",
  "eyebrow": null,
  "chip": null,
  "summary": "SEO capability pack operating on PROVIDED html/text (no network — fetching is the 'scraping' pack's job). Generates meta/OpenGraph/Twitter tags, schema.org JSON-LD...",
  "keywords": [
    "seo",
    "breadcrumblist",
    "on-page",
    "slugify",
    "pixel-ish",
    "seo api",
    "provided",
    "opengraph"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# seo adapter pack\n\nOn-page **SEO** capabilities that operate on **provided** html/text. Pure JS, zero npm deps.\n\n> **No network.** This pack never fetches a URL. Pulling remote HTML is the job of the\n> **`scraping`** pack — pass its output in here. (`scraping` also *parses* existing\n> sitemap.xml / robots.txt; this pack *generates* them.)\n\n## Tools\n\n| Tool | Args | Returns |\n|---|---|---|\n| `metaTags` | `{ title, description, url?, image?, type='website', twitterCard='summary_large_image', keywords? }` | `{ tags:[], html }` — title + description + canonical + OG + Twitter |\n| `openGraph` | `{ title?, description?, url?, image?, type='website' }` | `{ tags:[], html }` |\n| `twitterCard` | `{ title?, description?, image?, twitterCard='summary_large_image' }` | `{ tags:[], html }` |\n| `jsonLd` | `{ type, data }` | `{ type, json, script }` — schema.org for Article/Product/Organization/BreadcrumbList/FAQPage |\n| `sitemap` | `{ urls:[{loc,lastmod?,changefreq?,priority?}] }` | `{ xml, count }` — valid `<urlset>` |\n| `robotsTxt` | `{ rules:[{userAgent,allow?,disallow?}], sitemap? }` | `{ txt, blocks }` |\n| `audit` | `{ html }` | `{ score, issues:[], checks:{} }` — title/desc/h1/img-alt/canonical checks |\n| `keywordDensity` | `{ text, top=10 }` | `{ total, terms:[{term,count,density}] }` |\n| `slugify` | `{ text }` | `{ slug }` |\n| `readingTime` | `{ text, wpm=200 }` | `{ words, wpm, minutes, text }` |\n| `serpSnippet` | `{ title, description }` | `{ title, description, warnings }` — pixel-ish char limits |\n\n## Usage\n\n```js\nimport seo from './index.js';\n\nseo.adapters.metaTags({ title: 'Hello', description: 'A short but sufficient description of the page.', url: 'https://x.io' });\nseo.adapters.sitemap({ urls: [{ loc: 'https://x.io/', changefreq: 'daily', priority: 1 }] });\nseo.adapters.audit({ html: '<html><body><p>no title</p></body></html>' }); // → score/issues flag missing title\nseo.adapters.jsonLd({ type: 'Article', data: { title: 'T', author: 'A', datePublished: '2026-01-01' } });\n```\n\n## DRY boundaries\n\n- **Fetching stays in `scraping`.** This pack is offline-only.\n- **`slugify`** also exists in `a-transformation` (`string.slugify`). `seo.slugify` is a convenience\n  so an SEO caller need not cross packs; for heavy transliteration use `a-transformation`.\n",
  "source": {
    "path": "shared/engines/adapters/domain/seo/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 2483,
    "hash": "01b395ced07ef085bd04f3ae59fb7a782db1b2ae"
  },
  "urls": {
    "html": "/p/adapters/domain/seo",
    "json": "/docs/adapters/domain/seo.json",
    "md": "/docs/adapters/domain/seo.md"
  },
  "links": {
    "composes": [],
    "usedBy": [],
    "product": [],
    "howTo": [],
    "skills": []
  }
}
