sanity-plugin-seofields 1.6.0 → 1.6.2

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 (62) hide show
  1. package/dist/SeoHealthDashboard-FZTP4GS7.cjs +10 -0
  2. package/dist/{SeoHealthDashboard-7XMPVJRX.cjs.map → SeoHealthDashboard-FZTP4GS7.cjs.map} +1 -1
  3. package/dist/SeoHealthDashboard-PY5MKJCZ.js +4 -0
  4. package/dist/{SeoHealthDashboard-UWPLB5DM.js.map → SeoHealthDashboard-PY5MKJCZ.js.map} +1 -1
  5. package/dist/{SeoHealthTool-XCXINAQI.js → SeoHealthTool-SKY7FAKK.js} +3 -3
  6. package/dist/{SeoHealthTool-XCXINAQI.js.map → SeoHealthTool-SKY7FAKK.js.map} +1 -1
  7. package/dist/{SeoHealthTool-2H4XZR4I.cjs → SeoHealthTool-Z3O6NEKF.cjs} +4 -4
  8. package/dist/{SeoHealthTool-2H4XZR4I.cjs.map → SeoHealthTool-Z3O6NEKF.cjs.map} +1 -1
  9. package/dist/{SeoPreview-JDROKZLP.cjs → SeoPreview-PYYVZMY3.cjs} +41 -6
  10. package/dist/SeoPreview-PYYVZMY3.cjs.map +1 -0
  11. package/dist/{SeoPreview-F6GGPZWI.js → SeoPreview-XVAZYHCL.js} +43 -8
  12. package/dist/SeoPreview-XVAZYHCL.js.map +1 -0
  13. package/dist/{chunk-Z74QPO75.cjs → chunk-77U7CMJP.cjs} +12 -4
  14. package/dist/chunk-77U7CMJP.cjs.map +1 -0
  15. package/dist/{chunk-6NIHHOVS.js → chunk-IQG5JWVT.js} +2 -2
  16. package/dist/{chunk-6NIHHOVS.js.map → chunk-IQG5JWVT.js.map} +1 -1
  17. package/dist/{chunk-NHJBEV3A.js → chunk-KFFDQX22.js} +12 -4
  18. package/dist/chunk-KFFDQX22.js.map +1 -0
  19. package/dist/{chunk-KWUITSHS.js → chunk-ULFY5STC.js} +14 -14
  20. package/dist/chunk-ULFY5STC.js.map +1 -0
  21. package/dist/{chunk-WCLEWFAJ.cjs → chunk-XXQURVNE.cjs} +120 -120
  22. package/dist/chunk-XXQURVNE.cjs.map +1 -0
  23. package/dist/{chunk-7HCP5O62.cjs → chunk-YM3ZZ2HU.cjs} +2 -2
  24. package/dist/{chunk-7HCP5O62.cjs.map → chunk-YM3ZZ2HU.cjs.map} +1 -1
  25. package/dist/cli.js +1 -1
  26. package/dist/{component-7rqDvuy2.d.ts → component-CWZ0tlsq.d.ts} +7 -7
  27. package/dist/{component-J2nEQkOw.d.cts → component-DS-Ve_nw.d.cts} +7 -7
  28. package/dist/index.cjs +48 -41
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +57 -8
  31. package/dist/index.d.ts +57 -8
  32. package/dist/index.js +31 -20
  33. package/dist/index.js.map +1 -1
  34. package/dist/next.cjs +87 -88
  35. package/dist/next.cjs.map +1 -1
  36. package/dist/next.d.cts +4 -4
  37. package/dist/next.d.ts +4 -4
  38. package/dist/next.js +12 -9
  39. package/dist/next.js.map +1 -1
  40. package/dist/schema/next.cjs +80 -80
  41. package/dist/schema/next.d.cts +3 -3
  42. package/dist/schema/next.d.ts +3 -3
  43. package/dist/schema/next.js +3 -3
  44. package/dist/schema.cjs +153 -153
  45. package/dist/schema.cjs.map +1 -1
  46. package/dist/schema.d.cts +6 -6
  47. package/dist/schema.d.ts +6 -6
  48. package/dist/schema.js +2 -2
  49. package/dist/schema.js.map +1 -1
  50. package/dist/{types-BSgolLj3.d.cts → types-BjVpmBAX.d.cts} +1 -1
  51. package/dist/{types-BRn3hfQb.d.ts → types-Dy7r5det.d.ts} +1 -1
  52. package/package.json +1 -1
  53. package/dist/SeoHealthDashboard-7XMPVJRX.cjs +0 -10
  54. package/dist/SeoHealthDashboard-UWPLB5DM.js +0 -4
  55. package/dist/SeoPreview-F6GGPZWI.js.map +0 -1
  56. package/dist/SeoPreview-JDROKZLP.cjs.map +0 -1
  57. package/dist/chunk-KWUITSHS.js.map +0 -1
  58. package/dist/chunk-NHJBEV3A.js.map +0 -1
  59. package/dist/chunk-WCLEWFAJ.cjs.map +0 -1
  60. package/dist/chunk-Z74QPO75.cjs.map +0 -1
  61. package/dist/{types-DoUYMRVf.d.cts → types-BdaGoGQE.d.cts} +30 -30
  62. package/dist/{types-DnVvOp3o.d.ts → types-BwmZmt9I.d.ts} +30 -30
package/dist/cli.js CHANGED
@@ -61,7 +61,7 @@ ${e}`}function ft(e,t,n,o){a.success(`Updated ${e}`),a.dim(""),a.dim(" What was
61
61
  title,
62
62
  slug,
63
63
  seo
64
- } | order(_updatedAt desc)`;o.text="Fetching documents...";let c;try{c=await s.fetch(d);}catch(g){o.fail(`Failed to fetch: ${g.message}`),process.exit(1);}if(o.succeed(`Analysed ${c.length} document(s)`),c.length===0){a.warn("No documents with SEO fields found."),n&&Se(i);return}let u=c.map(g=>({doc:g,health:K(g)}));await gt(u,c,e),n&&Se(i);}async function gt(e,t,n){let o={excellent:0,good:0,fair:0,poor:0,missing:0},s=0;for(let{health:c}of e)o[c.status]=(o[c.status]||0)+1,s+=c.score;let i=Math.round(s/e.length);if(pt(t,i,o),n.format==="summary")return;n.format!=="table"&&(a.info(""),a.warn(`Unknown format "${n.format}", defaulting to table output.`)),St(e);let r={};for(let{health:c}of e)for(let u of c.issues)r[u]=(r[u]||0)+1;let d=Object.entries(r).sort(([,c],[,u])=>u-c).slice(0,10);d.length>0&&$t(d,t.length),a.info("");}function pt(e,t,n){a.heading("\u{1F4CA} Summary"),a.info(""),a.info(` Total documents: ${l.bold(String(e.length))}`),a.info(` Average score: ${l.bold(we(t))}%`),a.info(""),a.info(` ${A.excellent} Excellent (80+): ${n.excellent}`),a.info(` ${A.good} Good (60-79): ${n.good}`),a.info(` ${A.fair} Fair (40-59): ${n.fair}`),a.info(` ${A.poor} Poor (1-39): ${n.poor}`),a.info(` ${A.missing} Missing (0): ${n.missing}`);}var mt={excellent:"Excellent",good:"Good",fair:"Fair",poor:"Poor",missing:"Missing"},ht={excellent:l.green,good:l.blue,fair:l.yellow,poor:l.red,missing:l.dim};function yt(e,t=11){var s,i;let n=((s=mt[e])!=null?s:e).padEnd(t);return ((i=ht[e])!=null?i:(r=>r))(n)}function St(e){a.heading("\u{1F4CB} Documents"),a.info("");let t=Math.min(44,Math.max(5,...e.map(({doc:r})=>(r.title||r._id).length))),n=11,o=14,s=5,i=l.dim("\u2500".repeat(s+2+n+2+o+2+t));a.info(` ${l.dim("Score".padEnd(s))} ${l.dim("Status".padEnd(n))} ${l.dim("Type".padEnd(o))} ${l.dim("Title")}`),a.info(` ${i}`);for(let{doc:r,health:d}of e){let c=$e(r.title||r._id,t),u=String(d.score).padStart(s),f=yt(d.status,n),g=l.dim($e(r._type,o).padEnd(o));a.info(` ${we(d.score,u)} ${f} ${g} ${c}`);}}function $t(e,t){a.heading("\u{1F50D} Top Issues"),a.info("");for(let[n,o]of e){let s=Math.round(o/t*100);a.info(` ${l.red(String(o).padStart(4))} docs (${s}%) ${n}`);}}function Se(e){a.info(""),a.info(` ${l.dim("\u2500".repeat(52))}`),a.info(` ${l.dim("Connection info")}`),a.info(` ${l.dim("Project ID:")} ${l.white(e.projectId)} ${l.dim(`\u2190 ${e.sources.projectId}`)}`),a.info(` ${l.dim("Dataset: ")} ${l.white(e.dataset)} ${l.dim(`\u2190 ${e.sources.dataset}`)}`),a.info(` ${l.dim("Token: ")} ${l.dim(e.sources.token)}`),a.info("");}function we(e,t){let n=t!=null?t:String(e);return e>=80?l.green(n):e>=60?l.blue(n):e>=40?l.yellow(n):e>0?l.red(n):l.dim(n)}function $e(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e}H();var Z="1.6.0",ve=[l.cyan,e=>l.bold(l.blue(e)),l.blue,l.magenta,l.red,l.yellow],w=ve[Math.floor(Math.random()*ve.length)],Ce=["Run `seofields doctor` first to verify your setup is correct.","Use `seofields report --format summary` for a quick overview.","Export your SEO data before making bulk changes: `seofields export -o backup.json`.","Add `seoFields` type to every document schema to track SEO health.","A meta title between 50\u201360 characters gets the best click-through rate.","Meta descriptions should be 140\u2013160 characters for optimal display.","Open Graph images should be 1200\xD7630px for best social sharing.","Use `seofields config --baseUrl=https://yoursite.com` to enable canonical URLs.","Twitter Card images require a separate `twitterImage` field for best results.","Schema.org markup helps search engines understand your content structure.","Use `seofields report --types post,page` to filter by document type.","The `healthDashboard` tool gives a live view of SEO scores inside Sanity Studio.","Keywords should appear naturally \u2014 avoid keyword stuffing.","Every page needs a unique meta title. Duplicates hurt rankings.","Use `seofields export --format csv` to open SEO data in a spreadsheet.","Set `noIndex: true` on internal or draft pages to prevent indexing.","OG title and meta title can differ \u2014 OG is optimised for social, meta for search.","Run `seofields report` after content migrations to catch regressions.","Use `seofields init --schema-org` to add structured data support.","Structured data (Schema.org) can unlock rich results in Google Search.","A score of 80+ is excellent. Aim to get all key pages there.","The `seoPreview` option shows a live Google-style preview inside the editor.","Use `seofields report` in CI to catch SEO regressions before they ship.","Use `--dataset staging` to run reports against your staging dataset.","Keep your license key private \u2014 never commit it to version control.","Use `seofields config --healthDashboard.showDocumentId=true` for easier debugging.","Use `seofields export --format json --output report.json` to save SEO data to a file.","Alt text on images improves both accessibility and image search ranking.","Canonical URLs prevent duplicate content penalties from search engines.","A missing OG image means social shares show a blank card \u2014 always add one.","Use descriptive slugs: `/blog/seo-tips` ranks better than `/blog/post-123`.","Re-run `seofields report` monthly to track your SEO health over time.","The `types` filter helps you focus reports on high-priority content.","Use `seofields export` to back up SEO data before schema migrations.","Short meta titles (under 30 chars) waste valuable search result space.","Long meta descriptions get truncated \u2014 stay under 160 characters.","Twitter Cards need `twitter:card`, `twitter:title`, and `twitter:image` at minimum.","Use `seofields doctor` after upgrading the plugin to catch breaking changes.","JSON export includes health scores \u2014 pipe it into your analytics pipeline.","Set a `defaultHiddenFields` list to keep the SEO panel focused.","Internal links pass authority \u2014 make sure important pages are well-linked.","Page speed is a ranking factor \u2014 optimise images referenced in SEO fields.","Use consistent brand phrasing in meta titles across your site.","Structured data errors can be tested at schema.org/validator.","Focus first on pages with the most traffic, not just the lowest scores.","Add SEO review to your content publishing checklist.","Use `seofields config --healthDashboard.licenseKey=KEY` to unlock premium features.","The CSV export makes it easy to share SEO audits with non-technical stakeholders.","Every image on your page should have descriptive alt text.","Avoid duplicate meta descriptions \u2014 each page needs its own."];function bt(){return Ce[Math.floor(Math.random()*Ce.length)]}var wt=62,V=wt-2;function vt(e,t){let n=e.split(" "),o=[],s="";for(let i of n)s.length+(s?1:0)+i.length>t?(s&&o.push(s),s=i):s=s?`${s} ${i}`:i;return s&&o.push(s),o}function F(e,t){let n=V-3,o=" ".repeat(Math.max(0,n-t));return ` ${w("\u2502")} ${e}${o} ${w("\u2502")}`}function M(){return F("",0)}function xe(){let e="\u2500".repeat(V),t=bt(),n=V-3-5,o=vt(t,n);console.log(),console.log(` ${w(`\u256D${e}\u256E`)}`),console.log(M()),console.log(F(`${l.bold(l.green("seofields"))}${l.dim(` v${Z}`)}`,`seofields v${Z}`.length)),console.log(F(l.dim("SEO tooling for Sanity CMS \u2014 manage from your terminal"),54)),console.log(M());for(let i=0;i<o.length;i++){let r=i===0?`${l.dim("Tip: ")}${l.white(o[i])}`:` ${l.white(o[i])}`,d=5+o[i].length;console.log(F(r,d));}console.log(M()),console.log(` ${w(`\u2570${e}\u256F`)}`),console.log(),console.log(` ${l.bold("Commands")}`),console.log();let s=[["init ","Add seofields() to sanity.config"],["config ","Update plugin configuration options"],["create-config ","Create seofields.cli.ts / .js interactively"],["report ","SEO health report across all documents"],["export ","Export SEO fields as JSON or CSV"],["doctor ","Check setup, deps & config"]];for(let[i,r]of s)console.log(` ${w(i)} ${l.dim(r)}`);console.log(),console.log(` ${l.dim("Run ")}${l.white("seofields <command> --help")}${l.dim(" for details")}`),console.log();}function P(e,t){let n="\u2500".repeat(V),o=`seofields \u203A ${e}`;return ["",` ${w(`\u256D${n}\u256E`)}`,M(),F(`${l.bold(l.green("seofields"))}${w(" \u203A ")}${l.bold(w(e))}`,o.length),F(l.dim(t),t.length),M(),` ${w(`\u2570${n}\u256F`)}`].join(`
64
+ } | order(_updatedAt desc)`;o.text="Fetching documents...";let c;try{c=await s.fetch(d);}catch(g){o.fail(`Failed to fetch: ${g.message}`),process.exit(1);}if(o.succeed(`Analysed ${c.length} document(s)`),c.length===0){a.warn("No documents with SEO fields found."),n&&Se(i);return}let u=c.map(g=>({doc:g,health:K(g)}));await gt(u,c,e),n&&Se(i);}async function gt(e,t,n){let o={excellent:0,good:0,fair:0,poor:0,missing:0},s=0;for(let{health:c}of e)o[c.status]=(o[c.status]||0)+1,s+=c.score;let i=Math.round(s/e.length);if(pt(t,i,o),n.format==="summary")return;n.format!=="table"&&(a.info(""),a.warn(`Unknown format "${n.format}", defaulting to table output.`)),St(e);let r={};for(let{health:c}of e)for(let u of c.issues)r[u]=(r[u]||0)+1;let d=Object.entries(r).sort(([,c],[,u])=>u-c).slice(0,10);d.length>0&&$t(d,t.length),a.info("");}function pt(e,t,n){a.heading("\u{1F4CA} Summary"),a.info(""),a.info(` Total documents: ${l.bold(String(e.length))}`),a.info(` Average score: ${l.bold(we(t))}%`),a.info(""),a.info(` ${A.excellent} Excellent (80+): ${n.excellent}`),a.info(` ${A.good} Good (60-79): ${n.good}`),a.info(` ${A.fair} Fair (40-59): ${n.fair}`),a.info(` ${A.poor} Poor (1-39): ${n.poor}`),a.info(` ${A.missing} Missing (0): ${n.missing}`);}var mt={excellent:"Excellent",good:"Good",fair:"Fair",poor:"Poor",missing:"Missing"},ht={excellent:l.green,good:l.blue,fair:l.yellow,poor:l.red,missing:l.dim};function yt(e,t=11){var s,i;let n=((s=mt[e])!=null?s:e).padEnd(t);return ((i=ht[e])!=null?i:(r=>r))(n)}function St(e){a.heading("\u{1F4CB} Documents"),a.info("");let t=Math.min(44,Math.max(5,...e.map(({doc:r})=>(r.title||r._id).length))),n=11,o=14,s=5,i=l.dim("\u2500".repeat(s+2+n+2+o+2+t));a.info(` ${l.dim("Score".padEnd(s))} ${l.dim("Status".padEnd(n))} ${l.dim("Type".padEnd(o))} ${l.dim("Title")}`),a.info(` ${i}`);for(let{doc:r,health:d}of e){let c=$e(r.title||r._id,t),u=String(d.score).padStart(s),f=yt(d.status,n),g=l.dim($e(r._type,o).padEnd(o));a.info(` ${we(d.score,u)} ${f} ${g} ${c}`);}}function $t(e,t){a.heading("\u{1F50D} Top Issues"),a.info("");for(let[n,o]of e){let s=Math.round(o/t*100);a.info(` ${l.red(String(o).padStart(4))} docs (${s}%) ${n}`);}}function Se(e){a.info(""),a.info(` ${l.dim("\u2500".repeat(52))}`),a.info(` ${l.dim("Connection info")}`),a.info(` ${l.dim("Project ID:")} ${l.white(e.projectId)} ${l.dim(`\u2190 ${e.sources.projectId}`)}`),a.info(` ${l.dim("Dataset: ")} ${l.white(e.dataset)} ${l.dim(`\u2190 ${e.sources.dataset}`)}`),a.info(` ${l.dim("Token: ")} ${l.dim(e.sources.token)}`),a.info("");}function we(e,t){let n=t!=null?t:String(e);return e>=80?l.green(n):e>=60?l.blue(n):e>=40?l.yellow(n):e>0?l.red(n):l.dim(n)}function $e(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e}H();var Z="1.6.2",ve=[l.cyan,e=>l.bold(l.blue(e)),l.blue,l.magenta,l.red,l.yellow],w=ve[Math.floor(Math.random()*ve.length)],Ce=["Run `seofields doctor` first to verify your setup is correct.","Use `seofields report --format summary` for a quick overview.","Export your SEO data before making bulk changes: `seofields export -o backup.json`.","Add `seoFields` type to every document schema to track SEO health.","A meta title between 50\u201360 characters gets the best click-through rate.","Meta descriptions should be 140\u2013160 characters for optimal display.","Open Graph images should be 1200\xD7630px for best social sharing.","Use `seofields config --baseUrl=https://yoursite.com` to enable canonical URLs.","Twitter Card images require a separate `twitterImage` field for best results.","Schema.org markup helps search engines understand your content structure.","Use `seofields report --types post,page` to filter by document type.","The `healthDashboard` tool gives a live view of SEO scores inside Sanity Studio.","Keywords should appear naturally \u2014 avoid keyword stuffing.","Every page needs a unique meta title. Duplicates hurt rankings.","Use `seofields export --format csv` to open SEO data in a spreadsheet.","Set `noIndex: true` on internal or draft pages to prevent indexing.","OG title and meta title can differ \u2014 OG is optimised for social, meta for search.","Run `seofields report` after content migrations to catch regressions.","Use `seofields init --schema-org` to add structured data support.","Structured data (Schema.org) can unlock rich results in Google Search.","A score of 80+ is excellent. Aim to get all key pages there.","The `seoPreview` option shows a live Google-style preview inside the editor.","Use `seofields report` in CI to catch SEO regressions before they ship.","Use `--dataset staging` to run reports against your staging dataset.","Keep your license key private \u2014 never commit it to version control.","Use `seofields config --healthDashboard.showDocumentId=true` for easier debugging.","Use `seofields export --format json --output report.json` to save SEO data to a file.","Alt text on images improves both accessibility and image search ranking.","Canonical URLs prevent duplicate content penalties from search engines.","A missing OG image means social shares show a blank card \u2014 always add one.","Use descriptive slugs: `/blog/seo-tips` ranks better than `/blog/post-123`.","Re-run `seofields report` monthly to track your SEO health over time.","The `types` filter helps you focus reports on high-priority content.","Use `seofields export` to back up SEO data before schema migrations.","Short meta titles (under 30 chars) waste valuable search result space.","Long meta descriptions get truncated \u2014 stay under 160 characters.","Twitter Cards need `twitter:card`, `twitter:title`, and `twitter:image` at minimum.","Use `seofields doctor` after upgrading the plugin to catch breaking changes.","JSON export includes health scores \u2014 pipe it into your analytics pipeline.","Set a `defaultHiddenFields` list to keep the SEO panel focused.","Internal links pass authority \u2014 make sure important pages are well-linked.","Page speed is a ranking factor \u2014 optimise images referenced in SEO fields.","Use consistent brand phrasing in meta titles across your site.","Structured data errors can be tested at schema.org/validator.","Focus first on pages with the most traffic, not just the lowest scores.","Add SEO review to your content publishing checklist.","Use `seofields config --healthDashboard.licenseKey=KEY` to unlock premium features.","The CSV export makes it easy to share SEO audits with non-technical stakeholders.","Every image on your page should have descriptive alt text.","Avoid duplicate meta descriptions \u2014 each page needs its own."];function bt(){return Ce[Math.floor(Math.random()*Ce.length)]}var wt=62,V=wt-2;function vt(e,t){let n=e.split(" "),o=[],s="";for(let i of n)s.length+(s?1:0)+i.length>t?(s&&o.push(s),s=i):s=s?`${s} ${i}`:i;return s&&o.push(s),o}function F(e,t){let n=V-3,o=" ".repeat(Math.max(0,n-t));return ` ${w("\u2502")} ${e}${o} ${w("\u2502")}`}function M(){return F("",0)}function xe(){let e="\u2500".repeat(V),t=bt(),n=V-3-5,o=vt(t,n);console.log(),console.log(` ${w(`\u256D${e}\u256E`)}`),console.log(M()),console.log(F(`${l.bold(l.green("seofields"))}${l.dim(` v${Z}`)}`,`seofields v${Z}`.length)),console.log(F(l.dim("SEO tooling for Sanity CMS \u2014 manage from your terminal"),54)),console.log(M());for(let i=0;i<o.length;i++){let r=i===0?`${l.dim("Tip: ")}${l.white(o[i])}`:` ${l.white(o[i])}`,d=5+o[i].length;console.log(F(r,d));}console.log(M()),console.log(` ${w(`\u2570${e}\u256F`)}`),console.log(),console.log(` ${l.bold("Commands")}`),console.log();let s=[["init ","Add seofields() to sanity.config"],["config ","Update plugin configuration options"],["create-config ","Create seofields.cli.ts / .js interactively"],["report ","SEO health report across all documents"],["export ","Export SEO fields as JSON or CSV"],["doctor ","Check setup, deps & config"]];for(let[i,r]of s)console.log(` ${w(i)} ${l.dim(r)}`);console.log(),console.log(` ${l.dim("Run ")}${l.white("seofields <command> --help")}${l.dim(" for details")}`),console.log();}function P(e,t){let n="\u2500".repeat(V),o=`seofields \u203A ${e}`;return ["",` ${w(`\u256D${n}\u256E`)}`,M(),F(`${l.bold(l.green("seofields"))}${w(" \u203A ")}${l.bold(w(e))}`,o.length),F(l.dim(t),t.length),M(),` ${w(`\u2570${n}\u256F`)}`].join(`
65
65
  `)}program.name("seofields").description("CLI for sanity-plugin-seofields \u2014 manage SEO from your terminal").version(Z).action(xe);program.command("config",{isDefault:false}).description("Update seofields() configuration in your sanity.config file").addHelpText("before",P("config","Update seofields() configuration in your sanity.config file")).allowUnknownOption().allowExcessArguments().helpOption("-h, --help","Show help and all available options").addHelpText("after",["",` ${l.bold("Usage")}`,` ${l.dim("Pass any option as")} ${l.white("--key=value")}${l.dim(". Nested keys use dot notation.")}`,"",` ${l.bold("Top-level options")}`,` ${w("--baseUrl")}${l.dim("=<url>").padEnd(38)} ${l.dim("Canonical base URL")}`,` ${w("--seoPreview")}${l.dim("=<bool>").padEnd(36)} ${l.dim("Enable live Google-style preview")}`,` ${w("--defaultHiddenFields")}${l.dim("=<f1,f2>").padEnd(28)} ${l.dim("Comma-separated fields to hide")}`,` ${w("--types")}${l.dim("=<t1,t2>").padEnd(40)} ${l.dim("Document types that have SEO fields")}`,"",` ${l.bold("healthDashboard options")} ${l.dim("(prefix: --healthDashboard.<key>)")}`,` ${w("--healthDashboard.licenseKey")}${l.dim("=<key>").padEnd(22)} ${l.dim("License key for premium features")}`,` ${w("--healthDashboard.toolTitle")}${l.dim("=<str>").padEnd(23)} ${l.dim("Custom title shown in Studio")}`,` ${w("--healthDashboard.showDocumentId")}${l.dim("=<bool>").padEnd(17)} ${l.dim("Show document _id in dashboard")}`,` ${w("--healthDashboard.showHealthScore")}${l.dim("=<bool>").padEnd(16)} ${l.dim("Show score badge per document")}`,` ${w("--healthDashboard.query.types")}${l.dim("=<t1,t2>").padEnd(21)} ${l.dim("Filter dashboard by document types")}`,"",` ${l.bold("Examples")}`,` ${l.white("seofields config --baseUrl=https://mysite.com")}`,` ${l.white("seofields config --healthDashboard.licenseKey=SEOF-1234")}`,` ${l.white("seofields config --healthDashboard.showDocumentId=true --seoPreview=true")}`,` ${l.white("seofields config --healthDashboard.query.types=post,page")}`,` ${l.white("seofields config --defaultHiddenFields=metaImage,openGraphUrl")}`,""].join(`
66
66
  `)).action(()=>{let e=process.argv.indexOf("config"),t=e>=0?process.argv.slice(e+1):[];de(t);});program.command("create-config").description("Interactively create a seofields.cli.ts / .js config file").addHelpText("before",P("create-config","Interactively create a seofields.cli.ts / .js config file")).action(ue);program.command("init").description("Add seofields() plugin to your sanity.config file").addHelpText("before",P("init","Add seofields() plugin to your sanity.config file")).option("--preview","Enable SEO preview in the plugin config").option("--dashboard","Explicitly enable the SEO Health Dashboard").option("--no-dashboard","Disable the SEO Health Dashboard").option("--schema-org","Also add schemaOrg() plugin registration").addHelpText("after",["",` ${l.dim("Note: ")}${l.yellow("--preview")}${l.dim(", ")}${l.yellow("--dashboard")}${l.dim(", and ")}${l.yellow("--no-dashboard")}${l.dim(" only apply during initial setup.")}`,` ${l.dim(" If seofields() is already in your config, use:")}`,"",` ${l.dim(" ")}${l.white("seofields config --healthDashboard=true --seoPreview=true")}`,""].join(`
67
67
  `)).action(ye);program.command("export").description("Export all documents with SEO fields as JSON or CSV").addHelpText("before",P("export","Export all documents with SEO fields as JSON or CSV")).option("-p, --project-id <id>","Sanity project ID").option("-d, --dataset <name>","Sanity dataset name").option("-t, --token <token>","Sanity API token").option("--types <types>","Comma-separated document types to export (e.g. post,page)").option("-f, --format <format>","Output format: json or csv","json").option("-o, --output <path>","Output file path (defaults to stdout)").action(me);program.command("report").description("Generate an SEO health report for all documents").addHelpText("before",P("report","Generate an SEO health report for all documents")).option("-p, --project-id <id>","Sanity project ID").option("-d, --dataset <name>","Sanity dataset name").option("-t, --token <token>","Sanity API token").option("--types <types>","Comma-separated document types to include").option("--format <format>",'Output format: table or summary (default: "table")',"table").action(be);program.command("doctor").description("Check plugin configuration, dependencies, and setup").addHelpText("before",P("doctor","Check plugin configuration, dependencies, and setup")).option("--cwd <path>","Working directory to check",process.cwd()).action(ge);var _=process.argv.slice(2);_.length===1&&(_[0]==="--help"||_[0]==="-h")&&(xe(),process.exit(0));if(_.length>=2&&_[_.length-1]==="help"){let e=program.commands.find(t=>t.name()===_[0]);e&&(e.help(),process.exit(0));}program.parse();
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'react';
2
- import { L as SchemaOrgAggregateRatingData, N as SchemaOrgArticleData, P as SchemaOrgBlogPostingData, Q as SchemaOrgBookData, R as SchemaOrgBrandData, T as SchemaOrgBreadcrumbListData, U as SchemaOrgContactPointData, X as SchemaOrgCountryData, Y as SchemaOrgCourseData, _ as SchemaOrgEventData, $ as SchemaOrgFAQPageData, a0 as SchemaOrgHowToData, a2 as SchemaOrgImageObjectData, a3 as SchemaOrgItemListData, a4 as SchemaOrgJobPostingData, a5 as SchemaOrgLegalServiceData, a6 as SchemaOrgLocalBusinessData, a7 as SchemaOrgMovieData, a8 as SchemaOrgMusicAlbumData, a9 as SchemaOrgMusicRecordingData, aa as SchemaOrgNewsArticleData, ab as SchemaOrgOfferData, ac as SchemaOrgOrganizationData, ae as SchemaOrgPersonData, ag as SchemaOrgPlaceData, ah as SchemaOrgPostalAddressData, ai as SchemaOrgProductData, aj as SchemaOrgProfilePageData, ak as SchemaOrgRecipeData, al as SchemaOrgRestaurantData, an as SchemaOrgServiceData, am as SchemaOrgReviewData, ao as SchemaOrgSoftwareApplicationData, ar as SchemaOrgVideoObjectData, as as SchemaOrgWebApplicationData, at as SchemaOrgWebPageData, au as SchemaOrgWebsiteData } from './types-DnVvOp3o.js';
2
+ import { L as SchemaOrgAggregateRatingData, N as SchemaOrgArticleData, P as SchemaOrgBlogPostingData, Q as SchemaOrgBookData, R as SchemaOrgBrandData, T as SchemaOrgBreadcrumbListData, U as SchemaOrgContactPointData, X as SchemaOrgCountryData, Y as SchemaOrgCourseData, _ as SchemaOrgEventData, $ as SchemaOrgFAQPageData, a0 as SchemaOrgHowToData, a2 as SchemaOrgImageObjectData, a3 as SchemaOrgItemListData, a4 as SchemaOrgJobPostingData, a5 as SchemaOrgLegalServiceData, a6 as SchemaOrgLocalBusinessData, a7 as SchemaOrgMovieData, a8 as SchemaOrgMusicAlbumData, a9 as SchemaOrgMusicRecordingData, aa as SchemaOrgNewsArticleData, ab as SchemaOrgOfferData, ac as SchemaOrgOrganizationData, ae as SchemaOrgPersonData, ag as SchemaOrgPlaceData, ah as SchemaOrgPostalAddressData, ai as SchemaOrgProductData, aj as SchemaOrgProfilePageData, ak as SchemaOrgRecipeData, al as SchemaOrgRestaurantData, am as SchemaOrgReviewData, an as SchemaOrgServiceData, ao as SchemaOrgSoftwareApplicationData, ar as SchemaOrgVideoObjectData, as as SchemaOrgWebApplicationData, at as SchemaOrgWebPageData, au as SchemaOrgWebsiteData } from './types-BwmZmt9I.js';
3
3
  import { c as SanityImage } from './types-BtSRRG6C.js';
4
4
 
5
5
  /**
@@ -392,12 +392,6 @@ interface RestaurantSchemaProps {
392
392
  declare function buildRestaurantJsonLd(data?: SchemaOrgRestaurantData | null): Record<string, unknown> | null;
393
393
  declare function RestaurantSchema({ data }: RestaurantSchemaProps): JSX.Element | null;
394
394
 
395
- interface ServiceSchemaProps {
396
- data?: SchemaOrgServiceData | null;
397
- }
398
- declare function buildServiceJsonLd(data?: SchemaOrgServiceData | null): Record<string, unknown> | null;
399
- declare function ServiceSchema({ data }: ServiceSchemaProps): JSX.Element | null;
400
-
401
395
  interface ReviewSchemaProps {
402
396
  /** The Schema.org Review data from your Sanity GROQ query. */
403
397
  data?: SchemaOrgReviewData | null;
@@ -413,6 +407,12 @@ declare function buildReviewJsonLd(data?: SchemaOrgReviewData | null): Record<st
413
407
  */
414
408
  declare function ReviewSchema({ data }: ReviewSchemaProps): JSX.Element | null;
415
409
 
410
+ interface ServiceSchemaProps {
411
+ data?: SchemaOrgServiceData | null;
412
+ }
413
+ declare function buildServiceJsonLd(data?: SchemaOrgServiceData | null): Record<string, unknown> | null;
414
+ declare function ServiceSchema({ data }: ServiceSchemaProps): JSX.Element | null;
415
+
416
416
  /**
417
417
  * <SoftwareApplicationSchema> — Renders Schema.org SoftwareApplication JSON-LD structured data.
418
418
  *
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'react';
2
- import { L as SchemaOrgAggregateRatingData, N as SchemaOrgArticleData, P as SchemaOrgBlogPostingData, Q as SchemaOrgBookData, R as SchemaOrgBrandData, T as SchemaOrgBreadcrumbListData, U as SchemaOrgContactPointData, X as SchemaOrgCountryData, Y as SchemaOrgCourseData, _ as SchemaOrgEventData, $ as SchemaOrgFAQPageData, a0 as SchemaOrgHowToData, a2 as SchemaOrgImageObjectData, a3 as SchemaOrgItemListData, a4 as SchemaOrgJobPostingData, a5 as SchemaOrgLegalServiceData, a6 as SchemaOrgLocalBusinessData, a7 as SchemaOrgMovieData, a8 as SchemaOrgMusicAlbumData, a9 as SchemaOrgMusicRecordingData, aa as SchemaOrgNewsArticleData, ab as SchemaOrgOfferData, ac as SchemaOrgOrganizationData, ae as SchemaOrgPersonData, ag as SchemaOrgPlaceData, ah as SchemaOrgPostalAddressData, ai as SchemaOrgProductData, aj as SchemaOrgProfilePageData, ak as SchemaOrgRecipeData, al as SchemaOrgRestaurantData, an as SchemaOrgServiceData, am as SchemaOrgReviewData, ao as SchemaOrgSoftwareApplicationData, ar as SchemaOrgVideoObjectData, as as SchemaOrgWebApplicationData, at as SchemaOrgWebPageData, au as SchemaOrgWebsiteData } from './types-DoUYMRVf.cjs';
2
+ import { L as SchemaOrgAggregateRatingData, N as SchemaOrgArticleData, P as SchemaOrgBlogPostingData, Q as SchemaOrgBookData, R as SchemaOrgBrandData, T as SchemaOrgBreadcrumbListData, U as SchemaOrgContactPointData, X as SchemaOrgCountryData, Y as SchemaOrgCourseData, _ as SchemaOrgEventData, $ as SchemaOrgFAQPageData, a0 as SchemaOrgHowToData, a2 as SchemaOrgImageObjectData, a3 as SchemaOrgItemListData, a4 as SchemaOrgJobPostingData, a5 as SchemaOrgLegalServiceData, a6 as SchemaOrgLocalBusinessData, a7 as SchemaOrgMovieData, a8 as SchemaOrgMusicAlbumData, a9 as SchemaOrgMusicRecordingData, aa as SchemaOrgNewsArticleData, ab as SchemaOrgOfferData, ac as SchemaOrgOrganizationData, ae as SchemaOrgPersonData, ag as SchemaOrgPlaceData, ah as SchemaOrgPostalAddressData, ai as SchemaOrgProductData, aj as SchemaOrgProfilePageData, ak as SchemaOrgRecipeData, al as SchemaOrgRestaurantData, am as SchemaOrgReviewData, an as SchemaOrgServiceData, ao as SchemaOrgSoftwareApplicationData, ar as SchemaOrgVideoObjectData, as as SchemaOrgWebApplicationData, at as SchemaOrgWebPageData, au as SchemaOrgWebsiteData } from './types-BdaGoGQE.cjs';
3
3
  import { c as SanityImage } from './types-BtSRRG6C.cjs';
4
4
 
5
5
  /**
@@ -392,12 +392,6 @@ interface RestaurantSchemaProps {
392
392
  declare function buildRestaurantJsonLd(data?: SchemaOrgRestaurantData | null): Record<string, unknown> | null;
393
393
  declare function RestaurantSchema({ data }: RestaurantSchemaProps): JSX.Element | null;
394
394
 
395
- interface ServiceSchemaProps {
396
- data?: SchemaOrgServiceData | null;
397
- }
398
- declare function buildServiceJsonLd(data?: SchemaOrgServiceData | null): Record<string, unknown> | null;
399
- declare function ServiceSchema({ data }: ServiceSchemaProps): JSX.Element | null;
400
-
401
395
  interface ReviewSchemaProps {
402
396
  /** The Schema.org Review data from your Sanity GROQ query. */
403
397
  data?: SchemaOrgReviewData | null;
@@ -413,6 +407,12 @@ declare function buildReviewJsonLd(data?: SchemaOrgReviewData | null): Record<st
413
407
  */
414
408
  declare function ReviewSchema({ data }: ReviewSchemaProps): JSX.Element | null;
415
409
 
410
+ interface ServiceSchemaProps {
411
+ data?: SchemaOrgServiceData | null;
412
+ }
413
+ declare function buildServiceJsonLd(data?: SchemaOrgServiceData | null): Record<string, unknown> | null;
414
+ declare function ServiceSchema({ data }: ServiceSchemaProps): JSX.Element | null;
415
+
416
416
  /**
417
417
  * <SoftwareApplicationSchema> — Renders Schema.org SoftwareApplication JSON-LD structured data.
418
418
  *
package/dist/index.cjs CHANGED
@@ -4,21 +4,17 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var chunkIFDLKZET_cjs = require('./chunk-IFDLKZET.cjs');
6
6
  var chunkS367Y35J_cjs = require('./chunk-S367Y35J.cjs');
7
- var React12 = require('react');
7
+ var react = require('react');
8
8
  var sanity = require('sanity');
9
9
  var ui = require('@sanity/ui');
10
10
  var jsxRuntime = require('react/jsx-runtime');
11
11
 
12
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
-
14
- var React12__default = /*#__PURE__*/_interopDefault(React12);
15
-
16
12
  var MetaDescription = (props) => {
17
13
  const { value, renderDefault, path } = props;
18
14
  const parent = sanity.useFormValue([path[0]]);
19
15
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
20
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
21
- const feedbackItems = React12.useMemo(
16
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
17
+ const feedbackItems = react.useMemo(
22
18
  () => chunkIFDLKZET_cjs.getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
23
19
  [value, keywords, isParentseoField]
24
20
  );
@@ -40,7 +36,7 @@ var MetaImage = (props) => {
40
36
  const { value, renderDefault, path } = props;
41
37
  const seoParent = sanity.useFormValue([path[0]]);
42
38
  const hasImage = !!(value == null ? void 0 : value.asset);
43
- const feedbackItems = React12.useMemo(
39
+ const feedbackItems = react.useMemo(
44
40
  () => chunkIFDLKZET_cjs.getMetaImageValidation(hasImage, seoParent),
45
41
  [hasImage, seoParent]
46
42
  );
@@ -67,8 +63,8 @@ var MetaTitle = (props) => {
67
63
  const { value, renderDefault, path } = props;
68
64
  const parent = sanity.useFormValue([path[0]]);
69
65
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
70
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
71
- const feedbackItems = React12.useMemo(
66
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
67
+ const feedbackItems = react.useMemo(
72
68
  () => chunkIFDLKZET_cjs.getMetaTitleValidationMessages(value || "", keywords, isParentseoField),
73
69
  [value, keywords, isParentseoField]
74
70
  );
@@ -218,8 +214,8 @@ var OgDescription = (props) => {
218
214
  const { value, renderDefault, path } = props;
219
215
  const parent = sanity.useFormValue([path[0]]);
220
216
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
221
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
222
- const feedbackItems = React12.useMemo(
217
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
218
+ const feedbackItems = react.useMemo(
223
219
  () => chunkIFDLKZET_cjs.getOgDescriptionValidation(value || "", keywords, isParentseoField),
224
220
  [value, keywords, isParentseoField]
225
221
  );
@@ -248,7 +244,7 @@ var OgImage = (props) => {
248
244
  const imgValue = value;
249
245
  const hasImage = !!(imgValue == null ? void 0 : imgValue.asset);
250
246
  const altText = imgValue == null ? void 0 : imgValue.alt;
251
- const feedbackItems = React12.useMemo(
247
+ const feedbackItems = react.useMemo(
252
248
  () => chunkIFDLKZET_cjs.getOgImageValidation(hasImage, altText, seoParent),
253
249
  [hasImage, altText, seoParent]
254
250
  );
@@ -274,7 +270,7 @@ var OgImage_default = OgImage;
274
270
  var OgImageUrl = (props) => {
275
271
  const { value, renderDefault, path } = props;
276
272
  const seoParent = sanity.useFormValue([path[0]]);
277
- const feedbackItems = React12.useMemo(() => chunkIFDLKZET_cjs.getOgImageUrlValidation(value, seoParent), [value, seoParent]);
273
+ const feedbackItems = react.useMemo(() => chunkIFDLKZET_cjs.getOgImageUrlValidation(value, seoParent), [value, seoParent]);
278
274
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
279
275
  renderDefault(props),
280
276
  /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: feedbackItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 7 }, children: [
@@ -298,8 +294,8 @@ var OgTitle = (props) => {
298
294
  const { value, renderDefault, path } = props;
299
295
  const parent = sanity.useFormValue([path[0]]);
300
296
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
301
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
302
- const feedbackItems = React12.useMemo(
297
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
298
+ const feedbackItems = react.useMemo(
303
299
  () => chunkIFDLKZET_cjs.getOgTitleValidation(value || "", keywords, isParentseoField),
304
300
  [value, keywords, isParentseoField]
305
301
  );
@@ -442,8 +438,8 @@ var TwitterDescription = (props) => {
442
438
  const { value, renderDefault, path } = props;
443
439
  const parent = sanity.useFormValue([path[0]]);
444
440
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
445
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
446
- const feedbackItems = React12.useMemo(
441
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
442
+ const feedbackItems = react.useMemo(
447
443
  () => chunkIFDLKZET_cjs.getTwitterDescriptionValidation(value || "", keywords, isParentseoField),
448
444
  [value, keywords, isParentseoField]
449
445
  );
@@ -472,7 +468,7 @@ var TwitterImage = (props) => {
472
468
  const imgValue = value;
473
469
  const hasImage = !!(imgValue == null ? void 0 : imgValue.asset);
474
470
  const altText = imgValue == null ? void 0 : imgValue.alt;
475
- const feedbackItems = React12.useMemo(
471
+ const feedbackItems = react.useMemo(
476
472
  () => chunkIFDLKZET_cjs.getTwitterImageValidation(hasImage, altText, seoParent),
477
473
  [hasImage, altText, seoParent]
478
474
  );
@@ -498,7 +494,7 @@ var TwitterImage_default = TwitterImage;
498
494
  var TwitterImageUrl = (props) => {
499
495
  const { value, renderDefault, path } = props;
500
496
  const seoParent = sanity.useFormValue([path[0]]);
501
- const feedbackItems = React12.useMemo(
497
+ const feedbackItems = react.useMemo(
502
498
  () => chunkIFDLKZET_cjs.getTwitterImageUrlValidation(value, seoParent),
503
499
  [value, seoParent]
504
500
  );
@@ -525,8 +521,8 @@ var TwitterTitle = (props) => {
525
521
  const { value, renderDefault, path } = props;
526
522
  const parent = sanity.useFormValue([path[0]]);
527
523
  const isParentseoField = parent && (parent == null ? void 0 : parent._type) === "seoFields";
528
- const keywords = React12.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
529
- const feedbackItems = React12.useMemo(
524
+ const keywords = react.useMemo(() => (parent == null ? void 0 : parent.keywords) || [], [parent == null ? void 0 : parent.keywords]);
525
+ const feedbackItems = react.useMemo(
530
526
  () => chunkIFDLKZET_cjs.getTwitterTitleValidation(value || "", keywords, isParentseoField),
531
527
  [value, keywords, isParentseoField]
532
528
  );
@@ -661,8 +657,8 @@ function twitter(config = {}) {
661
657
  }
662
658
 
663
659
  // src/schemas/index.ts
664
- var LazySeoPreview = React12__default.default.lazy(() => import('./SeoPreview-JDROKZLP.cjs'));
665
- var SeoPreviewWrapper = (props) => React12__default.default.createElement(React12__default.default.Suspense, { fallback: null }, React12__default.default.createElement(LazySeoPreview, props));
660
+ var LazySeoPreview = react.lazy(() => import('./SeoPreview-PYYVZMY3.cjs'));
661
+ var SeoPreviewWrapper = (props) => react.createElement(react.Suspense, { fallback: null }, react.createElement(LazySeoPreview, props));
666
662
  function buildFieldGroupMap(groups) {
667
663
  const map = /* @__PURE__ */ new Map();
668
664
  for (const g of groups) {
@@ -723,9 +719,9 @@ function seoFieldsSchema(config = {}) {
723
719
  title: "SEO Preview",
724
720
  type: "string",
725
721
  components: { input: SeoPreviewWrapper },
726
- options: chunkS367Y35J_cjs.__spreadValues({
722
+ options: chunkS367Y35J_cjs.__spreadValues(chunkS367Y35J_cjs.__spreadValues(chunkS367Y35J_cjs.__spreadValues(chunkS367Y35J_cjs.__spreadValues(chunkS367Y35J_cjs.__spreadValues({
727
723
  baseUrl: config.baseUrl || "https://www.example.com"
728
- }, typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}),
724
+ }, config.apiVersion ? { apiVersion: config.apiVersion } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffix ? { titleSuffix: config.seoPreview.titleSuffix } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffixInheritColor ? { titleSuffixInheritColor: config.seoPreview.titleSuffixInheritColor } : {}), typeof config.seoPreview === "object" && config.seoPreview && config.seoPreview.titleSuffixQuery ? { titleSuffixQuery: config.seoPreview.titleSuffixQuery } : {}),
729
725
  initialValue: "",
730
726
  readOnly: true
731
727
  }),
@@ -987,9 +983,20 @@ function types(config = {}) {
987
983
  }
988
984
 
989
985
  // src/plugin.ts
990
- var resolveDashboardConfig = (healthDashboard) => {
991
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
986
+ var resolveDashboardConfig = (healthDashboard, rootApiVersion) => {
987
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
992
988
  const cfg = typeof healthDashboard === "object" ? healthDashboard : void 0;
989
+ const deprecationWarnings = [];
990
+ if ((cfg == null ? void 0 : cfg.apiVersion) !== void 0) {
991
+ deprecationWarnings.push({
992
+ key: "healthDashboard.apiVersion \u2192 apiVersion",
993
+ version: "v1.6.1",
994
+ changelogUrl: "https://github.com/hardik-143/sanity-plugin-seofields/blob/main/CHANGELOG.md"
995
+ });
996
+ console.warn(
997
+ '[sanity-plugin-seofields] "healthDashboard.apiVersion" is deprecated. Move it to the root "apiVersion" option instead.'
998
+ );
999
+ }
993
1000
  return {
994
1001
  enabled: healthDashboard !== false,
995
1002
  toolTitle: (_b = (_a = cfg == null ? void 0 : cfg.tool) == null ? void 0 : _a.title) != null ? _b : "SEO Health",
@@ -1002,15 +1009,15 @@ var resolveDashboardConfig = (healthDashboard) => {
1002
1009
  queryTypes: (_h = cfg == null ? void 0 : cfg.query) == null ? void 0 : _h.types,
1003
1010
  queryRequireSeo: (_i = cfg == null ? void 0 : cfg.query) == null ? void 0 : _i.requireSeo,
1004
1011
  queryGroq: (_j = cfg == null ? void 0 : cfg.query) == null ? void 0 : _j.groq,
1005
- apiVersion: cfg == null ? void 0 : cfg.apiVersion,
1012
+ apiVersion: (_k = cfg == null ? void 0 : cfg.apiVersion) != null ? _k : rootApiVersion,
1006
1013
  licenseKey: cfg == null ? void 0 : cfg.licenseKey,
1007
1014
  typeDisplayLabels: cfg == null ? void 0 : cfg.typeDisplayLabels,
1008
1015
  typeColumnMode: cfg == null ? void 0 : cfg.typeColumnMode,
1009
1016
  titleField: cfg == null ? void 0 : cfg.titleField,
1010
1017
  getDocumentBadge: cfg == null ? void 0 : cfg.getDocumentBadge,
1011
- loadingLicense: (_k = cfg == null ? void 0 : cfg.content) == null ? void 0 : _k.loadingLicense,
1012
- loadingDocuments: (_l = cfg == null ? void 0 : cfg.content) == null ? void 0 : _l.loadingDocuments,
1013
- noDocuments: (_m = cfg == null ? void 0 : cfg.content) == null ? void 0 : _m.noDocuments,
1018
+ loadingLicense: (_l = cfg == null ? void 0 : cfg.content) == null ? void 0 : _l.loadingLicense,
1019
+ loadingDocuments: (_m = cfg == null ? void 0 : cfg.content) == null ? void 0 : _m.loadingDocuments,
1020
+ noDocuments: (_n = cfg == null ? void 0 : cfg.content) == null ? void 0 : _n.noDocuments,
1014
1021
  previewMode: cfg == null ? void 0 : cfg.previewMode,
1015
1022
  structureTool: cfg == null ? void 0 : cfg.structureTool,
1016
1023
  exportEnabled: (() => {
@@ -1025,18 +1032,18 @@ var resolveDashboardConfig = (healthDashboard) => {
1025
1032
  if (typeof exportCfg === "object" && exportCfg.formats) return exportCfg.formats;
1026
1033
  return ["csv", "json"];
1027
1034
  })(),
1028
- compactStats: (_n = cfg == null ? void 0 : cfg.compactStats) != null ? _n : false,
1029
- deprecationWarnings: []
1035
+ compactStats: (_o = cfg == null ? void 0 : cfg.compactStats) != null ? _o : false,
1036
+ deprecationWarnings
1030
1037
  };
1031
1038
  };
1032
1039
  var seofields = sanity.definePlugin((config = {}) => {
1033
1040
  const { healthDashboard = true } = config;
1034
- const dash = resolveDashboardConfig(healthDashboard);
1035
- const LazySeoHealthTool = React12__default.default.lazy(() => import('./SeoHealthTool-2H4XZR4I.cjs'));
1036
- const BoundSeoHealthTool = () => React12__default.default.createElement(
1037
- React12__default.default.Suspense,
1041
+ const dash = resolveDashboardConfig(healthDashboard, config.apiVersion);
1042
+ const LazySeoHealthTool = react.lazy(() => import('./SeoHealthTool-Z3O6NEKF.cjs'));
1043
+ const BoundSeoHealthTool = () => react.createElement(
1044
+ react.Suspense,
1038
1045
  { fallback: null },
1039
- React12__default.default.createElement(LazySeoHealthTool, {
1046
+ react.createElement(LazySeoHealthTool, {
1040
1047
  icon: dash.icon,
1041
1048
  title: dash.title,
1042
1049
  description: dash.description,
@@ -1079,11 +1086,11 @@ var seofields = sanity.definePlugin((config = {}) => {
1079
1086
  });
1080
1087
  });
1081
1088
  var plugin_default = seofields;
1082
- var LazySeoHealthDashboard = React12__default.default.lazy(() => import('./SeoHealthDashboard-7XMPVJRX.cjs'));
1089
+ var LazySeoHealthDashboard = react.lazy(() => import('./SeoHealthDashboard-FZTP4GS7.cjs'));
1083
1090
  function createSeoHealthPane(optionsOrS, optionsWhenS) {
1084
1091
  const S = optionsOrS;
1085
1092
  const _a = optionsWhenS != null ? optionsWhenS : {}, { query, openInPane = true, title: paneTitle } = _a, rest = chunkS367Y35J_cjs.__objRest(_a, ["query", "openInPane", "title"]);
1086
- const SeoHealthPane = () => /* @__PURE__ */ jsxRuntime.jsx(React12__default.default.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
1093
+ const SeoHealthPane = () => /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: null, children: /* @__PURE__ */ jsxRuntime.jsx(
1087
1094
  LazySeoHealthDashboard,
1088
1095
  chunkS367Y35J_cjs.__spreadValues({
1089
1096
  customQuery: query,