{"_id":"@ai-rockstar/emdash-seo","_rev":"7-72246603b279401cf82301cf677bfd31","name":"@ai-rockstar/emdash-seo","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"@ai-rockstar/emdash-seo","version":"0.1.0","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.1.0","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"83e49e705610e5801fe1e40f6d21f25bb5d0aacf","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.1.0.tgz","fileCount":132,"integrity":"sha512-CSMehRa5Hmb4cMkyPnKRnGhHfxsPX7MG44DrbAp/LF/PdMzOvBIXyEpcfFPsdOyvv/JH+KysT3z/M0vXm/a3Gw==","signatures":[{"sig":"MEQCIBPwbVZIgP+YQ8QerLg0REGyMLFJncCXhnhFxdCbJBGkAiASqD2mPs/HCJOSF1rQ1ejWNrEEmeHSabV8ubUK/a23+g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":183271},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"bfa5a0bc8d22156c47d15067806b7100c40b0d2f","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.1.0_1775283255965_0.9765263838702918","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ai-rockstar/emdash-seo","version":"0.2.0","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.2.0","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"06d960af12b0ab195b45f7e686deaa5646a25d34","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.2.0.tgz","fileCount":164,"integrity":"sha512-OjHlhYZKPZb3R6TiWKfm2HsG1O6bQb2E51tGUAq7RihtVbnk9R+PAGV/pL/BnBtMxJOCS0CjO58IlpDWRRPsIw==","signatures":[{"sig":"MEUCIQDRFbawxefs9FBFqO1UpgMAdKrxXxAkh6qtLMv+p7lfSgIgR0xG9F2keJxhMf95brwAFDvWNyoNXySgXJnKAEGlcKc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":231975},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"0c8fa75a4a97c89448258adfa3fce0332e74c4b9","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.2.0_1775362725386_0.4263746331262499","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@ai-rockstar/emdash-seo","version":"0.2.1","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.2.1","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"e5ad6e89a8c3ccc4082a85ab6f07ce9a19966040","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.2.1.tgz","fileCount":166,"integrity":"sha512-VHDNCoFwT/oqvxAU6W2crjE+PTShSNl8e/wmlcZ77VMwfAk8ux/ou0ieyo9ejSAJGCeggZHMmIViCtIRCzeCRA==","signatures":[{"sig":"MEYCIQCc98jLgPguP5zvb9KwDQav7MbDCWYy0NJyzUIfGQoDbgIhAPoKYi0BtSce2NtdHX90cgxDre2c3GSre6zrB8gV84vE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":234071},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","gitHead":"c48cf4a016b7016672247be3b30f33e280346f09","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.2.1_1775447066733_0.9458500249332404","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@ai-rockstar/emdash-seo","version":"0.2.2","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.2.2","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"6e9a62693a6e47a45cde5909629d5f022ae32a40","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.2.2.tgz","fileCount":166,"integrity":"sha512-czhd49v3oHJqr7JXD3XB2hbP9CwnqxTZhNEgFccs/oFuxAnX7xWSmqfpTUW0KjkoYvJgs9tni+x1SQfzp24vFQ==","signatures":[{"sig":"MEUCIDsc8KwXfQL541+/CnWs2HZpiZbepdxr2gDmcrG2UYRvAiEAnbxd8IrVz/QtthHdFjj5SwAbS9UYTJtppUcmQkolKek=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":241095},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":"./dist/index.js","./admin":"./dist/admin/index.js"},"gitHead":"de17c7bf9202448029c1a5193c9fae85448c6d38","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.2.2_1775448938341_0.7352427678333933","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ai-rockstar/emdash-seo","version":"0.3.0","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.3.0","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"27988b79d3f1c0815f030aa81dc48460520da99d","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.3.0.tgz","fileCount":168,"integrity":"sha512-5/CKk7Jv0yqD21ymkgMR5gocuQFSpQ3wjatUMkV0spgSSa0dUQ3TIMbQivm678MCIgnEQ3M4PxZSU/SHZ9KGqg==","signatures":[{"sig":"MEQCIAnxTNytoMEoJGyKPdr+Q9V6LOod/vBhQxEom3uMhzMxAiASbqMqE1q4afZyEDzIq0/6w87lhwDBJ97PpiOA5RssNQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":240071},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":"./dist/index.js","./admin":"./dist/admin/index.js"},"gitHead":"fb36ab2ac7f089390245ea8f00460308f7fc19df","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.3.0_1775453934258_0.29505004021179015","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@ai-rockstar/emdash-seo","version":"0.3.1","license":"MIT","_id":"@ai-rockstar/emdash-seo@0.3.1","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"dist":{"shasum":"4399b0f5d4ac74df696e89aab117126693d9b4a9","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.3.1.tgz","fileCount":168,"integrity":"sha512-16bb16+7LJywnIZ15Mn3eu3OngE2Do2FTg0BNHRSVIu0oopkigHZdvPhli7I0J/llreDZTgQWdKEk9MhbXYZKA==","signatures":[{"sig":"MEUCIBNtfLb7FHMRXaR6uHPmasavK5VPRA5WyaSyS4RVU+8ZAiEAvNNgNjPeS0aTGxXOMjo4UBkjGn3d0fQW5EhyWtzeI2Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":240053},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":"./dist/index.js","./admin":"./dist/admin/index.js"},"gitHead":"fb36ab2ac7f089390245ea8f00460308f7fc19df","scripts":{"dev":"tsc --watch","lint":"npx oxlint src/ test/","test":"vitest run","build":"tsc","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"_npmVersion":"10.9.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","directories":{},"_nodeVersion":"23.9.0","_hasShrinkwrap":false,"devDependencies":{"zod":"^4.3.6","jsdom":"^29.0.1","react":"^19.2.4","emdash":"^0.1.0","vitest":"^4.1.2","react-dom":"^19.2.4","typescript":"^5.7.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"zod":"^4.3.6","emdash":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/emdash-seo_0.3.1_1775455511348_0.6150958788597845","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@ai-rockstar/emdash-seo","version":"0.3.2","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","type":"module","main":"dist/index.js","types":"dist/index.d.ts","license":"MIT","exports":{".":"./dist/index.js","./admin":"./dist/admin/index.js"},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","dev":"tsc --watch","test":"vitest run","test:watch":"vitest","lint":"npx oxlint src/ test/"},"peerDependencies":{"emdash":"^0.1.0","zod":"^4.3.6"},"devDependencies":{"@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.2","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","emdash":"^0.1.0","jsdom":"^29.0.1","react":"^19.2.4","react-dom":"^19.2.4","typescript":"^5.7.0","vitest":"^4.1.2","zod":"^4.3.6"},"_id":"@ai-rockstar/emdash-seo@0.3.2","gitHead":"c4672ab7bee714744577046ecbc4055c76d7654e","_nodeVersion":"23.9.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-FuN2LJpnUSfNCjPx37fQGHd+gIeK49iTy7fgr9F2atTTJ1Ulnb6utJYpAMxAz1mit0bGmdgQeC2v7V1deVjFNA==","shasum":"e7dd5c024296a147b30af96da93191d23455d48f","tarball":"https://registry.npmjs.org/@ai-rockstar/emdash-seo/-/emdash-seo-0.3.2.tgz","fileCount":168,"unpackedSize":232101,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDEHJ+LcTesl2+k3QVEt/9eeLJETVfOxJ5sCLjSz1QSbgIgFOKQaukvNddN76tXu8XA0LL97kSzDElaKitKzmAVkd0="}]},"_npmUser":{"name":"airockstar","email":"julien@roccaserra.com"},"directories":{},"maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/emdash-seo_0.3.2_1775456505462_0.23832196572482722"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-04T06:14:15.837Z","modified":"2026-04-06T06:21:45.786Z","0.1.0":"2026-04-04T06:14:16.120Z","0.2.0":"2026-04-05T04:18:45.518Z","0.2.1":"2026-04-06T03:44:26.893Z","0.2.2":"2026-04-06T04:15:38.565Z","0.3.0":"2026-04-06T05:38:54.424Z","0.3.1":"2026-04-06T06:05:11.495Z","0.3.2":"2026-04-06T06:21:45.664Z"},"license":"MIT","description":"SEO toolkit for Emdash CMS — meta tags, OpenGraph, JSON-LD, sitemaps, and content analysis","maintainers":[{"name":"airockstar","email":"julien@roccaserra.com"}],"readme":"# @emdash-seo/toolkit\n\nThe complete SEO toolkit for Emdash CMS -- meta tags, sitemaps, structured data, content analysis, and social sharing.\n\n[![npm version](https://img.shields.io/npm/v/@emdash-seo/toolkit)](https://www.npmjs.com/package/@emdash-seo/toolkit)\n[![license](https://img.shields.io/npm/l/@emdash-seo/toolkit)](./LICENSE)\n[![tests](https://img.shields.io/badge/tests-505%20passing-brightgreen)]()\n\n---\n\n## Features\n\n### Free Tier\n\n**Meta Tags**\n- Configurable title template with `{title}` and `{site}` placeholders\n- Customizable title separator (`|`, `-`, `--`, `*`)\n- Meta description with length validation\n- Robots directive (index/noindex, follow/nofollow) with per-content override\n- Canonical URL (auto-detect + manual override)\n\n**OpenGraph**\n- `og:title`, `og:description`, `og:image`, `og:url`, `og:type`\n- `og:site_name`, `og:locale`\n- Article-specific tags: `article:published_time`, `article:modified_time`, `article:author`, `article:section`\n- Fallback chain: per-content override > page SEO > page data > global defaults\n\n**Twitter Cards**\n- Automatic card type selection (`summary` vs `summary_large_image`)\n- `twitter:title`, `twitter:description`, `twitter:image`\n- `twitter:site` and `twitter:creator` from global settings\n\n**JSON-LD Structured Data**\n- `Article` schema for blog posts (headline, datePublished, author, publisher)\n- `WebPage` schema for generic pages\n- `BreadcrumbList` schema based on URL path\n- `Organization` schema from global settings\n- `WebSite` schema with `SearchAction` (sitelinks searchbox, homepage only)\n\n**XML Sitemap**\n- Auto-generated from all published content\n- `<lastmod>`, `<changefreq>`, `<priority>` per entry\n- Sitemap index with per-collection splitting\n- Respects `noindex` overrides (excluded automatically)\n\n**robots.txt**\n- Dynamic generation with configurable allow/disallow rules\n- Auto-includes sitemap URL\n- Crawl-delay setting\n\n**Site Verification**\n- Google Search Console\n- Bing Webmaster Tools\n- Pinterest\n- Yandex\n\n**Analytics Injection**\n- Google Analytics 4 (gtag.js)\n- Google Tag Manager (head + body noscript)\n- Cloudflare Web Analytics\n- Facebook Pixel (inline + noscript fallback)\n- Custom scripts with head/body placement control\n\n**Content Analysis (Basic)**\n- Title length check (30-60 characters optimal)\n- Description length check (120-160 characters optimal)\n- Focus keyword presence in title and description\n- Heading hierarchy validation (single H1, proper nesting)\n- Image alt text audit\n- OG image validation\n\n**SEO Scoring**\n- 0-100 weighted score per content item\n- Auto-analyze on content save (`content:afterSave` hook)\n- Weekly cron recalculation (Sunday 3am)\n- Scores stored for dashboard aggregation\n\n**hreflang / Multi-Language**\n- `hreflang` tag generation for multilingual sites\n- Configurable language mappings via JSON\n\n**Admin UI**\n- SEO Overrides page: table view with inline editing, collection filter, delete\n- Content Analysis page: run free/advanced analysis, score badge, check list\n- SERP preview (Google search result mock with truncation)\n- Social preview (Facebook, Twitter, LinkedIn card previews)\n- Character counters with color thresholds on title and description\n- Dashboard widgets: SEO Status (missing fields summary) and SEO Score (site-wide average + distribution)\n- Inline field widget for content editor SEO fields\n\n### Pro Tier ($49/year)\n\n- **Advanced readability:** Flesch-Kincaid score, passive voice detection, sentence length analysis, transition word usage, paragraph length checks\n- **Keyword density analysis** with word-boundary matching\n- **Keyword in first paragraph** check\n- **Internal link suggestions** based on content similarity\n- **Alt text suggestions** from image context\n- **Duplicate title/description detection** across the entire site\n- **Social auto-posting** to Twitter/X and Bluesky (AT Protocol)\n- **Bulk SEO editing** for batch override updates\n\n### Agency Tier ($199/year)\n\n- Multi-site license (up to 999 sites)\n- White-label support\n\n---\n\n## Installation\n\n```bash\nnpm install @emdash-seo/toolkit\n```\n\nThen add the plugin to your `astro.config.mjs`:\n\n```javascript\nimport seoToolkit from \"@ai-rockstar/emdash-seo\";\n\n// Inside your emdash() integration config:\nemdash({\n  plugins: [seoToolkit()],\n  // ... your other config\n})\n```\n\n---\n\n## Configuration\n\nAll settings are managed through the Emdash admin panel. The plugin auto-generates a settings form from the schema below.\n\n### SEO Defaults\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `siteName` | Your site's name, used in title templates and JSON-LD | `\"\"` |\n| `titleTemplate` | Title format with `{title}` and `{site}` placeholders | `\"{title} \\| {site}\"` |\n| `titleSeparator` | Character between title parts (`\\|`, `-`, `--`, `*`) | `\"\\|\"` |\n| `defaultOgImage` | Fallback OpenGraph image URL | `\"\"` |\n| `twitterHandle` | Site-level Twitter @handle for `twitter:site` | `\"\"` |\n| `orgName` | Organization name for JSON-LD `Organization` schema | `\"\"` |\n| `orgLogoUrl` | Organization logo URL for JSON-LD | `\"\"` |\n| `defaultRobots` | Default robots directive for all pages | `\"index, follow\"` |\n\n### Analytics & Tracking\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `googleAnalyticsId` | GA4 measurement ID (e.g., `G-XXXXXXX`) | `\"\"` |\n| `gtmContainerId` | Google Tag Manager container ID (e.g., `GTM-XXXXXXX`) | `\"\"` |\n| `cfAnalyticsToken` | Cloudflare Web Analytics beacon token | `\"\"` |\n| `facebookPixelId` | Facebook Pixel ID | `\"\"` |\n| `customHeadScripts` | Custom scripts injected into `<head>` | `\"\"` |\n| `customBodyScripts` | Custom scripts injected before `</body>` | `\"\"` |\n\n### Sitemap & Indexing\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `sitemapEnabled` | Enable XML sitemap generation | `true` |\n| `sitemapExclude` | Comma-separated list of collections to exclude | `\"\"` |\n| `sitemapDefaultChangefreq` | Default change frequency (`daily`, `weekly`, `monthly`) | `\"weekly\"` |\n| `sitemapDefaultPriority` | Default priority (0.0-1.0) | `0.5` |\n| `robotsTxtCustom` | Custom robots.txt rules (multiline) | `\"\"` |\n| `robotsCrawlDelay` | Crawl delay in seconds (0-60) | `0` |\n\n### Site Verification\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `googleVerification` | Google Search Console verification code | `\"\"` |\n| `bingVerification` | Bing Webmaster Tools verification code | `\"\"` |\n| `pinterestVerification` | Pinterest verification code | `\"\"` |\n| `yandexVerification` | Yandex verification code | `\"\"` |\n\n### Social & Sharing\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `enableAutoPost` | Auto-post to social platforms on publish | `false` |\n| `twitterApiKey` | Twitter API key (stored as secret) | -- |\n| `twitterApiSecret` | Twitter API secret (stored as secret) | -- |\n| `blueskyHandle` | Bluesky handle | `\"\"` |\n| `blueskyAppPassword` | Bluesky app password (stored as secret) | -- |\n| `socialPostTemplate` | Post template with `{title}`, `{url}`, `{description}` | `\"New: {title} -- {url}\"` |\n\n### Multi-Language\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `hreflangEnabled` | Enable hreflang tag generation | `false` |\n| `hreflangMappings` | Language mappings as JSON | `\"\"` |\n\n### Licensing\n\n| Setting | Description |\n|---------|-------------|\n| `licenseKey` | License key for Pro/Agency features (stored as secret) |\n\n---\n\n## Structured Data\n\nThe plugin generates JSON-LD structured data automatically based on page type and context.\n\n### Auto-generated schemas\n\n| Schema | When |\n|--------|------|\n| `Article` | Content pages with article metadata (publishedTime, author) |\n| `WebPage` | All other pages |\n| `BreadcrumbList` | All pages (derived from URL path) |\n| `Organization` | When `orgName` and `orgLogoUrl` are configured |\n| `WebSite` | Homepage only, includes `SearchAction` for sitelinks searchbox |\n\n### Per-content schema types\n\nSet a custom schema type on any content item via the SEO overrides API:\n\n| Schema | `schemaType` value |\n|--------|-------------------|\n| FAQ | `\"faq\"` |\n| HowTo | `\"howto\"` |\n| Product | `\"product\"` |\n| LocalBusiness | `\"localBusiness\"` |\n| Event | `\"event\"` |\n\nUse the `schemaData` field to pass type-specific properties:\n\n```typescript\nawait fetch(\"/_plugins/@emdash-seo/toolkit/overrides/save\", {\n  method: \"POST\",\n  body: JSON.stringify({\n    contentId: \"my-article\",\n    collection: \"posts\",\n    schemaType: \"faq\",\n    schemaData: {\n      questions: [\n        { question: \"What is Emdash?\", answer: \"A modern headless CMS.\" },\n      ],\n    },\n  }),\n});\n```\n\n---\n\n## API Routes\n\nAll routes are available at `/_plugins/@emdash-seo/toolkit/<route>`.\n\n| Route | Auth | Description |\n|-------|------|-------------|\n| `overrides/save` | Admin | Save SEO overrides for a content item |\n| `overrides/get` | Admin | Get SEO overrides for a content item |\n| `overrides/list` | Admin | List all overrides (paginated, filterable by collection) |\n| `overrides/delete` | Admin | Delete overrides for a content item |\n| `overrides/bulk-save` | Admin | Bulk save overrides (Pro) |\n| `sitemap-xml` | Public | XML sitemap or sitemap index |\n| `sitemap-collection` | Public | Per-collection XML sitemap |\n| `robots-txt` | Public | Dynamic robots.txt |\n| `analytics/status` | Admin | SEO audit summary (missing titles, descriptions, OG images) |\n| `analyze` | Admin | Run basic content analysis (free) |\n| `analyze/advanced` | Admin | Run full content analysis (Pro) |\n| `analyze/link-suggestions` | Admin | Get internal link suggestions (Pro) |\n| `scores/list` | Admin | List SEO scores (paginated, filterable by collection) |\n| `social/post` | Admin | Post to social platforms (Pro) |\n| `social/history` | Admin | View social posting history (paginated) |\n| `license/validate` | Admin | Validate and store a license key |\n| `license/status` | Admin | Check current license status and tier |\n\n---\n\n## Development\n\n```bash\npnpm install        # install dependencies\npnpm dev            # watch mode (TypeScript compiler)\npnpm test           # run tests (vitest)\npnpm typecheck      # type check\npnpm lint           # lint (oxlint)\npnpm build          # build\n```\n\nThe test suite contains 505 tests across 46 files covering hooks, routes, analysis, schemas, admin components, and utilities.\n\n---\n\n## Architecture\n\nThe plugin is built on the Emdash plugin API (`definePlugin`) and runs on the Cloudflare Workers runtime.\n\n### Hooks\n\n| Hook | Purpose |\n|------|---------|\n| `page:metadata` | Generates meta tags, OpenGraph, Twitter Cards, and JSON-LD |\n| `page:fragments` | Injects analytics scripts, verification tags, and hreflang |\n| `content:afterSave` | Auto-analyzes content on save, triggers social auto-posting |\n| `cron` | Weekly SEO score recalculation |\n| `plugin:install` / `plugin:activate` | Lifecycle management |\n\n### Capabilities\n\n- `read:content` -- read content for analysis and sitemap generation\n- `read:users` -- read user data for author attribution\n- `read:media` -- validate OG images\n- `page:inject` -- inject scripts and tags into page output\n- `network:fetch` -- call external APIs (Twitter, Bluesky)\n\n### Storage Collections\n\n| Collection | Purpose | Key Indexes |\n|------------|---------|-------------|\n| `overrides` | Per-content SEO field overrides | `contentId` (unique), `collection` |\n| `scores` | SEO analysis scores | `contentId` (unique), `collection`, `score` |\n| `socialPosts` | Social posting history | `contentId`, `platform`, `postedAt` |\n\n### Admin UI\n\nReact-based admin interface with two pages (SEO Overrides, Content Analysis), two dashboard widgets (SEO Status, SEO Score), and an inline field widget for the content editor. Uses a design system with shared tokens, global styles, and reusable components (SerpPreview, SocialPreview, CharacterCounter, ScoreBadge).\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}