sanity-plugin-seofields 1.5.4 → 1.6.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 (70) hide show
  1. package/README.md +4 -4
  2. package/dist/SeoHealthDashboard-7XMPVJRX.cjs +10 -0
  3. package/dist/{SeoHealthDashboard-KPBNXSL4.cjs.map → SeoHealthDashboard-7XMPVJRX.cjs.map} +1 -1
  4. package/dist/SeoHealthDashboard-UWPLB5DM.js +4 -0
  5. package/dist/{SeoHealthDashboard-QKVB5HK3.js.map → SeoHealthDashboard-UWPLB5DM.js.map} +1 -1
  6. package/dist/{SeoHealthTool-ON3SRXCF.cjs → SeoHealthTool-2H4XZR4I.cjs} +4 -4
  7. package/dist/{SeoHealthTool-ON3SRXCF.cjs.map → SeoHealthTool-2H4XZR4I.cjs.map} +1 -1
  8. package/dist/{SeoHealthTool-EPPOEDTW.js → SeoHealthTool-XCXINAQI.js} +3 -3
  9. package/dist/{SeoHealthTool-EPPOEDTW.js.map → SeoHealthTool-XCXINAQI.js.map} +1 -1
  10. package/dist/{SeoPreview-G3LPA7GV.js → SeoPreview-F6GGPZWI.js} +2 -2
  11. package/dist/SeoPreview-F6GGPZWI.js.map +1 -0
  12. package/dist/{SeoPreview-Y3CFDVBR.cjs → SeoPreview-JDROKZLP.cjs} +2 -2
  13. package/dist/SeoPreview-JDROKZLP.cjs.map +1 -0
  14. package/dist/chunk-6NIHHOVS.js +3918 -0
  15. package/dist/chunk-6NIHHOVS.js.map +1 -0
  16. package/dist/chunk-7HCP5O62.cjs +4027 -0
  17. package/dist/chunk-7HCP5O62.cjs.map +1 -0
  18. package/dist/{chunk-527WXITP.js → chunk-KWUITSHS.js} +218 -54
  19. package/dist/chunk-KWUITSHS.js.map +1 -0
  20. package/dist/{chunk-UCVSMPEJ.js → chunk-NHJBEV3A.js} +2 -2
  21. package/dist/{chunk-UCVSMPEJ.js.map → chunk-NHJBEV3A.js.map} +1 -1
  22. package/dist/chunk-WCLEWFAJ.cjs +669 -0
  23. package/dist/chunk-WCLEWFAJ.cjs.map +1 -0
  24. package/dist/{chunk-G2SVI2SP.cjs → chunk-Z74QPO75.cjs} +2 -2
  25. package/dist/{chunk-G2SVI2SP.cjs.map → chunk-Z74QPO75.cjs.map} +1 -1
  26. package/dist/cli.js +25 -25
  27. package/dist/component-7rqDvuy2.d.ts +534 -0
  28. package/dist/component-J2nEQkOw.d.cts +534 -0
  29. package/dist/index.cjs +159 -185
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +43 -51
  32. package/dist/index.d.ts +43 -51
  33. package/dist/index.js +159 -185
  34. package/dist/index.js.map +1 -1
  35. package/dist/next.cjs +155 -51
  36. package/dist/next.d.cts +3 -3
  37. package/dist/next.d.ts +3 -3
  38. package/dist/next.js +2 -2
  39. package/dist/schema/next.cjs +171 -52
  40. package/dist/schema/next.cjs.map +1 -1
  41. package/dist/schema/next.d.cts +12 -428
  42. package/dist/schema/next.d.ts +12 -428
  43. package/dist/schema/next.js +20 -2
  44. package/dist/schema/next.js.map +1 -1
  45. package/dist/schema.cjs +831 -156
  46. package/dist/schema.cjs.map +1 -1
  47. package/dist/schema.d.cts +318 -41
  48. package/dist/schema.d.ts +318 -41
  49. package/dist/schema.js +567 -86
  50. package/dist/schema.js.map +1 -1
  51. package/dist/types-BRn3hfQb.d.ts +24 -0
  52. package/dist/types-BSgolLj3.d.cts +24 -0
  53. package/dist/{types-R3n9Fu4w.d.cts → types-BtSRRG6C.d.cts} +1 -1
  54. package/dist/{types-R3n9Fu4w.d.ts → types-BtSRRG6C.d.ts} +1 -1
  55. package/dist/types-DnVvOp3o.d.ts +1215 -0
  56. package/dist/types-DoUYMRVf.d.cts +1215 -0
  57. package/package.json +2 -1
  58. package/dist/SeoHealthDashboard-KPBNXSL4.cjs +0 -10
  59. package/dist/SeoHealthDashboard-QKVB5HK3.js +0 -4
  60. package/dist/SeoPreview-G3LPA7GV.js.map +0 -1
  61. package/dist/SeoPreview-Y3CFDVBR.cjs.map +0 -1
  62. package/dist/chunk-527WXITP.js.map +0 -1
  63. package/dist/chunk-6CYMVS3O.js +0 -1245
  64. package/dist/chunk-6CYMVS3O.js.map +0 -1
  65. package/dist/chunk-D2GWRRK5.cjs +0 -1293
  66. package/dist/chunk-D2GWRRK5.cjs.map +0 -1
  67. package/dist/chunk-L3L3FSPJ.cjs +0 -478
  68. package/dist/chunk-L3L3FSPJ.cjs.map +0 -1
  69. package/dist/types-CVaAX7uy.d.cts +0 -589
  70. package/dist/types-Ci-ZZT7A.d.ts +0 -589
package/dist/cli.js CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
- import {program}from'commander';import c from'picocolors';import x from'fs';import w from'path';import {createClient}from'@sanity/client';import {pathToFileURL}from'url';import*as $ from'@clack/prompts';import ct from'ora';var xe=Object.defineProperty;var ee=Object.getOwnPropertySymbols;var ke=Object.prototype.hasOwnProperty,je=Object.prototype.propertyIsEnumerable;var te=(e,t,n)=>t in e?xe(e,t,{enumerable:true,configurable:true,writable:true,value:n}):e[t]=n,N=(e,t)=>{for(var n in t||(t={}))ke.call(t,n)&&te(e,n,t[n]);if(ee)for(var n of ee(t))je.call(t,n)&&te(e,n,t[n]);return e};var a={info:e=>console.log(c.blue("\u2139"),e),success:e=>console.log(c.green("\u2714"),e),warn:e=>console.log(c.yellow("\u26A0"),e),error:e=>console.log(c.red("\u2716"),e),dim:e=>console.log(c.dim(e)),heading:e=>console.log(`
3
- ${c.bold(c.cyan(e))}`),table:e=>{if(e.length===0)return;let t=e[0].map((n,o)=>Math.max(...e.map(s=>(s[o]||"").length)));for(let n of e)console.log(n.map((o,s)=>(o||"").padEnd(t[s]+2)).join(""));}},A={excellent:c.green("\u25CF"),good:c.blue("\u25CF"),fair:c.yellow("\u25CF"),poor:c.red("\u25CF"),missing:c.dim("\u25CB")};({excellent:c.green("Excellent"),good:c.blue("Good"),fair:c.yellow("Fair"),poor:c.red("Poor"),missing:c.dim("Missing")});var Ee=[".env",".env.local",".env.development.local",".env.development"];function Te(e){let t={};for(let n of e.split(`
4
- `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<0)continue;let i=o.slice(0,s).trim(),r=o.slice(s+1).trim();(r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'"))&&(r=r.slice(1,-1)),t[i]=r;}return t}var oe=false;function U(e=process.cwd()){if(!oe){oe=true;for(let t of Ee){let n=w.join(e,t);if(x.existsSync(n))try{let o=Te(x.readFileSync(n,"utf-8"));for(let[s,i]of Object.entries(o))process.env[s]===void 0&&(process.env[s]=i);}catch(o){}}}}var Re=["seofields.cli.js","seofields.cli.mjs","seofields.cli.cjs","seofields.cli.ts","seofields.cli.tsx"];function V(e,t){let n=e.match(new RegExp(`${t}\\s*:\\s*['"\`]([^'"\`]+)['"\`]`));if(n)return n[1];let o=e.match(new RegExp(`${t}\\s*:\\s*process\\.env\\.([A-Z_a-z0-9]+)`));if(o)return process.env[o[1]]}function De(e){return e.split(`
2
+ import {program}from'commander';import l from'picocolors';import I from'fs';import C from'path';import {createClient}from'@sanity/client';import {pathToFileURL}from'url';import*as b from'@clack/prompts';import ct from'ora';var Ie=Object.defineProperty;var ee=Object.getOwnPropertySymbols;var ke=Object.prototype.hasOwnProperty,je=Object.prototype.propertyIsEnumerable;var te=(e,t,n)=>t in e?Ie(e,t,{enumerable:true,configurable:true,writable:true,value:n}):e[t]=n,N=(e,t)=>{for(var n in t||(t={}))ke.call(t,n)&&te(e,n,t[n]);if(ee)for(var n of ee(t))je.call(t,n)&&te(e,n,t[n]);return e};var a={info:e=>console.log(l.blue("\u2139"),e),success:e=>console.log(l.green("\u2714"),e),warn:e=>console.log(l.yellow("\u26A0"),e),error:e=>console.log(l.red("\u2716"),e),dim:e=>console.log(l.dim(e)),heading:e=>console.log(`
3
+ ${l.bold(l.cyan(e))}`),table:e=>{if(e.length===0)return;let t=e[0].map((n,o)=>Math.max(...e.map(s=>(s[o]||"").length)));for(let n of e)console.log(n.map((o,s)=>(o||"").padEnd(t[s]+2)).join(""));}},A={excellent:l.green("\u25CF"),good:l.blue("\u25CF"),fair:l.yellow("\u25CF"),poor:l.red("\u25CF"),missing:l.dim("\u25CB")};({excellent:l.green("Excellent"),good:l.blue("Good"),fair:l.yellow("Fair"),poor:l.red("Poor"),missing:l.dim("Missing")});var Ee=[".env",".env.local",".env.development.local",".env.development"];function Te(e){let t={};for(let n of e.split(`
4
+ `)){let o=n.trim();if(!o||o.startsWith("#"))continue;let s=o.indexOf("=");if(s<0)continue;let i=o.slice(0,s).trim(),r=o.slice(s+1).trim();(r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'"))&&(r=r.slice(1,-1)),t[i]=r;}return t}var oe=false;function H(e=process.cwd()){if(!oe){oe=true;for(let t of Ee){let n=C.join(e,t);if(I.existsSync(n))try{let o=Te(I.readFileSync(n,"utf-8"));for(let[s,i]of Object.entries(o))process.env[s]===void 0&&(process.env[s]=i);}catch(o){}}}}var Re=["seofields.cli.js","seofields.cli.mjs","seofields.cli.cjs","seofields.cli.ts","seofields.cli.tsx"];function W(e,t){let n=e.match(new RegExp(`${t}\\s*:\\s*['"\`]([^'"\`]+)['"\`]`));if(n)return n[1];let o=e.match(new RegExp(`${t}\\s*:\\s*process\\.env\\.([A-Z_a-z0-9]+)`));if(o)return process.env[o[1]]}function De(e){return e.split(`
5
5
  `).filter(t=>!/^\s*\/\//.test(t)).join(`
6
- `)}async function Fe(e){var t;try{let o=await import(pathToFileURL(e).href),s=(t=o==null?void 0:o.default)!=null?t:o;return s&&typeof s=="object"?s:null}catch(n){return null}}function Pe(e){try{let t=x.readFileSync(e,"utf-8"),n=De(t),o=V(n,"projectId"),s=V(n,"dataset"),i=V(n,"token"),r=n.match(/types\s*:\s*\[([^\]]+)\]/),l;r&&(l=r[1].split(",").map(f=>f.trim().replace(/['"`]/g,"")).filter(Boolean));let d=n.match(/showConnectionInfo\s*:\s*(true|false)/),g=d?d[1]==="true":void 0;return !o&&!s&&!i&&!l&&g===void 0?null:{projectId:o,dataset:s,token:i,types:l,showConnectionInfo:g}}catch(t){return null}}var R;async function D(e=process.cwd()){if(R!==void 0)return R!=null?R:{};U(e);for(let t of Re){let n=w.join(e,t);if(!x.existsSync(n))continue;let s=t.endsWith(".ts")||t.endsWith(".tsx")?Pe(n):await Fe(n);if(s)return R=s,s}return R=null,{}}var ie=["sanity.config.ts","sanity.config.js","sanity.config.mjs","sanity.config.tsx"];function Me(e){for(let t of ie){let n=w.join(e,t);if(!x.existsSync(n))continue;let o=x.readFileSync(n,"utf-8"),s=o.match(/projectId\s*:\s*['"`]([a-z0-9-]+)['"`]/),i=o.match(/dataset\s*:\s*['"`]([a-z0-9_-]+)['"`]/);return {projectId:s==null?void 0:s[1],dataset:i==null?void 0:i[1]}}return {}}function T(e=process.cwd()){for(let t of ie){let n=w.join(e,t);if(x.existsSync(n))return n}return null}async function Ue(e={},t=process.cwd()){let n=e.projectId,o=e.dataset,s=e.token,i={projectId:"",dataset:"",token:""};n&&(i.projectId="--project-id flag"),o&&(i.dataset="--dataset flag"),s&&(i.token="--token flag");let r=await D(t),d=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(m=>{let p=w.join(t,m);return x.existsSync(p)}),g=d||"seofields.cli.*";!n&&r.projectId&&(n=r.projectId,i.projectId=g),!o&&r.dataset&&(o=r.dataset,i.dataset=g),!s&&r.token&&(s=r.token,i.token=g);let f=process.env.SANITY_PROJECT_ID||process.env.SANITY_STUDIO_PROJECT_ID,u=process.env.SANITY_DATASET||process.env.SANITY_STUDIO_DATASET;if(!n&&f){n=f;let m=process.env.SANITY_PROJECT_ID?"SANITY_PROJECT_ID":"SANITY_STUDIO_PROJECT_ID";i.projectId=`.env \u2192 ${m}`;}if(!o&&u){o=u;let m=process.env.SANITY_DATASET?"SANITY_DATASET":"SANITY_STUDIO_DATASET";i.dataset=`.env \u2192 ${m}`;}if(!n||!o){let m=Me(t),p=T(t),b=p?w.basename(p):"sanity.config.*";!n&&m.projectId&&(n=m.projectId,i.projectId=b),!o&&m.dataset&&(o=m.dataset,i.dataset=b);}if(!n)throw new Error(`Could not determine Sanity project ID.
6
+ `)}async function Fe(e){var t;try{let o=await import(pathToFileURL(e).href),s=(t=o==null?void 0:o.default)!=null?t:o;return s&&typeof s=="object"?s:null}catch(n){return null}}function Pe(e){try{let t=I.readFileSync(e,"utf-8"),n=De(t),o=W(n,"projectId"),s=W(n,"dataset"),i=W(n,"token"),r=n.match(/types\s*:\s*\[([^\]]+)\]/),d;r&&(d=r[1].split(",").map(f=>f.trim().replace(/['"`]/g,"")).filter(Boolean));let c=n.match(/showConnectionInfo\s*:\s*(true|false)/),u=c?c[1]==="true":void 0;return !o&&!s&&!i&&!d&&u===void 0?null:{projectId:o,dataset:s,token:i,types:d,showConnectionInfo:u}}catch(t){return null}}var R;async function D(e=process.cwd()){if(R!==void 0)return R!=null?R:{};H(e);for(let t of Re){let n=C.join(e,t);if(!I.existsSync(n))continue;let s=t.endsWith(".ts")||t.endsWith(".tsx")?Pe(n):await Fe(n);if(s)return R=s,s}return R=null,{}}var ie=["sanity.config.ts","sanity.config.js","sanity.config.mjs","sanity.config.tsx"];function Me(e){for(let t of ie){let n=C.join(e,t);if(!I.existsSync(n))continue;let o=I.readFileSync(n,"utf-8"),s=o.match(/projectId\s*:\s*['"`]([a-z0-9-]+)['"`]/),i=o.match(/dataset\s*:\s*['"`]([a-z0-9_-]+)['"`]/);return {projectId:s==null?void 0:s[1],dataset:i==null?void 0:i[1]}}return {}}function T(e=process.cwd()){for(let t of ie){let n=C.join(e,t);if(I.existsSync(n))return n}return null}async function Ue(e={},t=process.cwd()){let n=e.projectId,o=e.dataset,s=e.token,i={projectId:"",dataset:"",token:""};n&&(i.projectId="--project-id flag"),o&&(i.dataset="--dataset flag"),s&&(i.token="--token flag");let r=await D(t),c=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(m=>{let p=C.join(t,m);return I.existsSync(p)}),u=c||"seofields.cli.*";!n&&r.projectId&&(n=r.projectId,i.projectId=u),!o&&r.dataset&&(o=r.dataset,i.dataset=u),!s&&r.token&&(s=r.token,i.token=u);let f=process.env.SANITY_PROJECT_ID||process.env.SANITY_STUDIO_PROJECT_ID,g=process.env.SANITY_DATASET||process.env.SANITY_STUDIO_DATASET;if(!n&&f){n=f;let m=process.env.SANITY_PROJECT_ID?"SANITY_PROJECT_ID":"SANITY_STUDIO_PROJECT_ID";i.projectId=`.env \u2192 ${m}`;}if(!o&&g){o=g;let m=process.env.SANITY_DATASET?"SANITY_DATASET":"SANITY_STUDIO_DATASET";i.dataset=`.env \u2192 ${m}`;}if(!n||!o){let m=Me(t),p=T(t),y=p?C.basename(p):"sanity.config.*";!n&&m.projectId&&(n=m.projectId,i.projectId=y),!o&&m.dataset&&(o=m.dataset,i.dataset=y);}if(!n)throw new Error(`Could not determine Sanity project ID.
7
7
  Options:
8
8
  1. Create a seofields.cli.ts file with defineSeoCli({ projectId: "..." })
9
9
  2. Pass --project-id flag
10
- 3. Set SANITY_PROJECT_ID env var`);o||(o="production",i.dataset="default");let y=process.env.SANITY_TOKEN||process.env.SANITY_AUTH_TOKEN;return !s&&y&&(s=y,i.token=process.env.SANITY_TOKEN?".env \u2192 SANITY_TOKEN":".env \u2192 SANITY_AUTH_TOKEN"),i.token||(i.token="none (unauthenticated)"),{projectId:n,dataset:o,token:s,sources:i}}async function Y(e={}){let t=await Ue(e);return {client:createClient(N({projectId:t.projectId,dataset:t.dataset,apiVersion:e.apiVersion||"2024-01-01",useCdn:false},t.token?{token:t.token}:{})),resolved:t}}var He=new Set(["types","defaultHiddenFields"]);function Le(e){let t={};for(let n=0;n<e.length;n++){let o=e[n];if(!o.startsWith("--"))continue;let s=o.slice(2);if(s.includes("=")){let i=s.indexOf("=");t[s.slice(0,i)]=s.slice(i+1);}else n+1<e.length&&!e[n+1].startsWith("--")?t[s]=e[++n]:t[s]="true";}return t}function Ye(e,t){return e==="true"?true:e==="false"?false:/^\d+$/.test(e)?parseInt(e,10):/^\d+\.\d+$/.test(e)?parseFloat(e):He.has(t)&&e.includes(",")?e.split(",").map(n=>n.trim()):e}function Ge(e){let t={};for(let[n,o]of Object.entries(e)){let s=n.split("."),i=t;for(let l=0;l<s.length-1;l++){let d=s[l];(typeof i[d]!="object"||Array.isArray(i[d]))&&(i[d]={}),i=i[d];}let r=s[s.length-1];i[r]=Ye(o,r);}return t}function J(e,t){return typeof e=="string"?`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`:typeof e=="boolean"||typeof e=="number"?String(e):Array.isArray(e)?`[${e.map(n=>J(n,t)).join(", ")}]`:typeof e=="object"&&e!==null?q(e,t):String(e)}function q(e,t){let n=Object.entries(e);if(n.length===0)return "{}";let o=" ".repeat(t),s=" ".repeat(Math.max(0,t-2));return `{
11
- ${n.map(([r,l])=>`${o}${r}: ${J(l,t+2)},`).join(`
10
+ 3. Set SANITY_PROJECT_ID env var`);o||(o="production",i.dataset="default");let S=process.env.SANITY_TOKEN||process.env.SANITY_AUTH_TOKEN;return !s&&S&&(s=S,i.token=process.env.SANITY_TOKEN?".env \u2192 SANITY_TOKEN":".env \u2192 SANITY_AUTH_TOKEN"),i.token||(i.token="none (unauthenticated)"),{projectId:n,dataset:o,token:s,sources:i}}async function G(e={}){let t=await Ue(e);return {client:createClient(N({projectId:t.projectId,dataset:t.dataset,apiVersion:e.apiVersion||"2024-01-01",useCdn:false},t.token?{token:t.token}:{})),resolved:t}}var He=new Set(["types","defaultHiddenFields"]);function Le(e){let t={};for(let n=0;n<e.length;n++){let o=e[n];if(!o.startsWith("--"))continue;let s=o.slice(2);if(s.includes("=")){let i=s.indexOf("=");t[s.slice(0,i)]=s.slice(i+1);}else n+1<e.length&&!e[n+1].startsWith("--")?t[s]=e[++n]:t[s]="true";}return t}function Ye(e,t){return e==="true"?true:e==="false"?false:/^\d+$/.test(e)?parseInt(e,10):/^\d+\.\d+$/.test(e)?parseFloat(e):He.has(t)&&e.includes(",")?e.split(",").map(n=>n.trim()):e}function Ge(e){let t={};for(let[n,o]of Object.entries(e)){let s=n.split("."),i=t;for(let d=0;d<s.length-1;d++){let c=s[d];(typeof i[c]!="object"||Array.isArray(i[c]))&&(i[c]={}),i=i[c];}let r=s[s.length-1];i[r]=Ye(o,r);}return t}function B(e,t){return typeof e=="string"?`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`:typeof e=="boolean"||typeof e=="number"?String(e):Array.isArray(e)?`[${e.map(n=>B(n,t)).join(", ")}]`:typeof e=="object"&&e!==null?J(e,t):String(e)}function J(e,t){let n=Object.entries(e);if(n.length===0)return "{}";let o=" ".repeat(t),s=" ".repeat(Math.max(0,t-2));return `{
11
+ ${n.map(([r,d])=>`${o}${r}: ${B(d,t+2)},`).join(`
12
12
  `)}
13
- ${s}}`}function B(e,t,n,o){if(e[t]!==n)return null;let s=0,i=t;for(;i<e.length;){let r=e[i];if(r===n)s++;else if(r===o){if(s--,s===0)return {inner:e.slice(t+1,i),outerStart:t,outerEnd:i+1}}else if(r==='"'||r==="'"||r==="`"){let l=r;for(i++;i<e.length;){if(e[i]==="\\"){i+=2;continue}if(e[i]===l)break;i++;}}i++;}return null}function ce(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function W(e,t,n,o){let s=J(n,o+2),i=new RegExp(`((?:^|\\n)([ \\t]*))(${ce(t)})(\\s*:\\s*)([^\\n{[]+?)(,?)(?=\\s*(?:\\n|$|[,}]))`);if(i.test(e))return e.replace(i,(d,g,f,u,y)=>`${g}${u}${y}${s},`);let r=/\n([ \t]+)\w/.exec(e),l=r?r[1]:" ".repeat(o);return `${e.trimEnd()}
14
- ${l}${t}: ${s},
15
- `}function le(e,t,n=2){let o=e;for(let[s,i]of Object.entries(t)){if(!(typeof i=="object"&&i!==null&&!Array.isArray(i))){o=W(o,s,i,n);continue}let d=new RegExp(`\\b${ce(s)}\\s*:`).exec(o);if(!d){o=W(o,s,i,n);continue}let g=d.index+d[0].length,f=o.slice(g).search(/\S/),u=g+(f>=0?f:0);if(o[u]!=="{"){o=W(o,s,i,n);continue}let y=B(o,u,"{","}");if(!y)continue;let m=le(y.inner,i,n+2),p=o.slice(0,d.index).match(/\n([ \t]*)$/),b=p?p[1]:" ".repeat(n);o=o.slice(0,y.outerStart+1)+m+b+o.slice(y.outerEnd-1);}return o}function Ke(e){a.info("Applying config:");for(let[t,n]of Object.entries(e))a.dim(` ${c.cyan(t)}: ${c.yellow(String(n))}`);}function Ve(e){let t=/seofields\s*\(/.exec(e);(!t||t.index===void 0)&&(a.error("`seofields()` not found in config. Run `seofields init` first."),process.exit(1));let n=t.index+t[0].length-1,o=B(e,n,"(",")");return o||(a.error("Could not parse the seofields() call \u2014 please check your config file syntax."),process.exit(1)),{callIndex:t.index,parenBlock:o}}function We(e,t,n,o){let s=n.inner.trim();if(!s){let i=e.lastIndexOf(`
16
- `,t)+1,r=t-i,l=r+2;return a.dim(" (Injecting fresh config into empty seofields())"),`
17
- ${" ".repeat(l)}${q(o,l+2)},
18
- ${" ".repeat(r)}`}if(s.startsWith("{")){let i=n.inner.indexOf("{"),r=B(n.inner,i,"{","}");r||(a.error("Could not parse the existing config object \u2014 check syntax."),process.exit(1));let l=le(r.inner,o,2),d=n.inner.slice(0,r.outerStart),g=n.inner.slice(r.outerEnd);return a.dim(" (Merging into existing config object)"),`${d}{${l}}${g}`}return a.warn(`Config uses a variable reference (\`${s.slice(0,30)}\u2026\`) \u2014 cannot auto-update.`),a.dim(" Add the following manually to your config object:"),a.dim(q(o,2)),null}async function de(e){if(a.heading("seofields config"),e.length===0){ae();return}let t=Le(e);Object.keys(t).length===0&&(a.error("No valid --key=value options found."),ae(),process.exit(1));let n=Ge(t);Ke(t);let o=T(process.cwd());o||(a.error("No sanity.config.ts/js found. Run from your Sanity project root."),process.exit(1)),a.info(`Updating ${o}`);let s=x.readFileSync(o,"utf-8"),{callIndex:i,parenBlock:r}=Ve(s),l=We(s,i,r,n);if(l===null)return;let d=s.slice(0,r.outerStart+1)+l+s.slice(r.outerEnd-1);x.writeFileSync(o,d,"utf-8"),a.success(`Config updated in ${o}`);}function ae(){console.log(""),console.log(` ${c.bold("Usage:")} seofields config [--option=value ...]`),console.log(""),console.log(` ${c.bold("Top-level options:")}`),console.log(` ${c.cyan("--baseUrl")}=<url> Base URL of your site`),console.log(` ${c.cyan("--seoPreview")}=true|false Enable SERP preview in Studio`),console.log(` ${c.cyan("--defaultHiddenFields")}=field1,field2 Fields hidden by default`),console.log(""),console.log(` ${c.bold("Health Dashboard options:")}`),console.log(` ${c.cyan("--healthDashboard")}=true|false Enable/disable dashboard`),console.log(` ${c.cyan("--healthDashboard.licenseKey")}=SEOF-XXXX-\u2026 License key`),console.log(` ${c.cyan("--healthDashboard.toolTitle")}=<title> Studio nav tab label`),console.log(` ${c.cyan("--healthDashboard.showTypeColumn")}=true|false`),console.log(` ${c.cyan("--healthDashboard.showDocumentId")}=true|false`),console.log(` ${c.cyan("--healthDashboard.previewMode")}=true|false Show demo data`),console.log(` ${c.cyan("--healthDashboard.apiVersion")}=2024-01-01`),console.log(` ${c.cyan("--healthDashboard.typeColumnMode")}=badge|text`),console.log(` ${c.cyan("--healthDashboard.structureTool")}=<name>`),console.log(""),console.log(` ${c.bold("Query options:")}`),console.log(` ${c.cyan("--healthDashboard.query.types")}=post,page Limit to doc types`),console.log(` ${c.cyan("--healthDashboard.query.requireSeo")}=true|false`),console.log(` ${c.cyan("--healthDashboard.query.groq")}=<query> Custom GROQ query`),console.log(""),console.log(` ${c.bold("Examples:")}`),console.log(c.dim(" seofields config --baseUrl=https://example.com")),console.log(c.dim(" seofields config --healthDashboard.licenseKey=SEOF-777F-4C32-B154 --healthDashboard.showDocumentId=false")),console.log(c.dim(" seofields config --healthDashboard.query.types=post,page --seoPreview=true")),console.log("");}var qe=(e,t)=>`import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'
13
+ ${s}}`}function z(e,t,n,o){if(e[t]!==n)return null;let s=0,i=t;for(;i<e.length;){let r=e[i];if(r===n)s++;else if(r===o){if(s--,s===0)return {inner:e.slice(t+1,i),outerStart:t,outerEnd:i+1}}else if(r==='"'||r==="'"||r==="`"){let d=r;for(i++;i<e.length;){if(e[i]==="\\"){i+=2;continue}if(e[i]===d)break;i++;}}i++;}return null}function ce(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function q(e,t,n,o){let s=B(n,o+2),i=new RegExp(`((?:^|\\n)([ \\t]*))(${ce(t)})(\\s*:\\s*)([^\\n{[]+?)(,?)(?=\\s*(?:\\n|$|[,}]))`);if(i.test(e))return e.replace(i,(c,u,f,g,S)=>`${u}${g}${S}${s},`);let r=/\n([ \t]+)\w/.exec(e),d=r?r[1]:" ".repeat(o);return `${e.trimEnd()}
14
+ ${d}${t}: ${s},
15
+ `}function le(e,t,n=2){let o=e;for(let[s,i]of Object.entries(t)){if(!(typeof i=="object"&&i!==null&&!Array.isArray(i))){o=q(o,s,i,n);continue}let c=new RegExp(`\\b${ce(s)}\\s*:`).exec(o);if(!c){o=q(o,s,i,n);continue}let u=c.index+c[0].length,f=o.slice(u).search(/\S/),g=u+(f>=0?f:0);if(o[g]!=="{"){o=q(o,s,i,n);continue}let S=z(o,g,"{","}");if(!S)continue;let m=le(S.inner,i,n+2),p=o.slice(0,c.index).match(/\n([ \t]*)$/),y=p?p[1]:" ".repeat(n);o=o.slice(0,S.outerStart+1)+m+y+o.slice(S.outerEnd-1);}return o}function Ke(e){a.info("Applying config:");for(let[t,n]of Object.entries(e))a.dim(` ${l.cyan(t)}: ${l.yellow(String(n))}`);}function Ve(e){let t=/seofields\s*\(/.exec(e);(!t||t.index===void 0)&&(a.error("`seofields()` not found in config. Run `seofields init` first."),process.exit(1));let n=t.index+t[0].length-1,o=z(e,n,"(",")");return o||(a.error("Could not parse the seofields() call \u2014 please check your config file syntax."),process.exit(1)),{callIndex:t.index,parenBlock:o}}function We(e,t,n,o){let s=n.inner.trim();if(!s){let i=e.lastIndexOf(`
16
+ `,t)+1,r=t-i,d=r+2;return a.dim(" (Injecting fresh config into empty seofields())"),`
17
+ ${" ".repeat(d)}${J(o,d+2)},
18
+ ${" ".repeat(r)}`}if(s.startsWith("{")){let i=n.inner.indexOf("{"),r=z(n.inner,i,"{","}");r||(a.error("Could not parse the existing config object \u2014 check syntax."),process.exit(1));let d=le(r.inner,o,2),c=n.inner.slice(0,r.outerStart),u=n.inner.slice(r.outerEnd);return a.dim(" (Merging into existing config object)"),`${c}{${d}}${u}`}return a.warn(`Config uses a variable reference (\`${s.slice(0,30)}\u2026\`) \u2014 cannot auto-update.`),a.dim(" Add the following manually to your config object:"),a.dim(J(o,2)),null}async function de(e){if(a.heading("seofields config"),e.length===0){ae();return}let t=Le(e);Object.keys(t).length===0&&(a.error("No valid --key=value options found."),ae(),process.exit(1));let n=Ge(t);Ke(t);let o=T(process.cwd());o||(a.error("No sanity.config.ts/js found. Run from your Sanity project root."),process.exit(1)),a.info(`Updating ${o}`);let s=I.readFileSync(o,"utf-8"),{callIndex:i,parenBlock:r}=Ve(s),d=We(s,i,r,n);if(d===null)return;let c=s.slice(0,r.outerStart+1)+d+s.slice(r.outerEnd-1);I.writeFileSync(o,c,"utf-8"),a.success(`Config updated in ${o}`);}function ae(){console.log(""),console.log(` ${l.bold("Usage:")} seofields config [--option=value ...]`),console.log(""),console.log(` ${l.bold("Top-level options:")}`),console.log(` ${l.cyan("--baseUrl")}=<url> Base URL of your site`),console.log(` ${l.cyan("--seoPreview")}=true|false Enable SERP preview in Studio`),console.log(` ${l.cyan("--defaultHiddenFields")}=field1,field2 Fields hidden by default`),console.log(""),console.log(` ${l.bold("Health Dashboard options:")}`),console.log(` ${l.cyan("--healthDashboard")}=true|false Enable/disable dashboard`),console.log(` ${l.cyan("--healthDashboard.licenseKey")}=SEOF-XXXX-\u2026 License key`),console.log(` ${l.cyan("--healthDashboard.toolTitle")}=<title> Studio nav tab label`),console.log(` ${l.cyan("--healthDashboard.showTypeColumn")}=true|false`),console.log(` ${l.cyan("--healthDashboard.showDocumentId")}=true|false`),console.log(` ${l.cyan("--healthDashboard.previewMode")}=true|false Show demo data`),console.log(` ${l.cyan("--healthDashboard.apiVersion")}=2024-01-01`),console.log(` ${l.cyan("--healthDashboard.typeColumnMode")}=badge|text`),console.log(` ${l.cyan("--healthDashboard.structureTool")}=<name>`),console.log(""),console.log(` ${l.bold("Query options:")}`),console.log(` ${l.cyan("--healthDashboard.query.types")}=post,page Limit to doc types`),console.log(` ${l.cyan("--healthDashboard.query.requireSeo")}=true|false`),console.log(` ${l.cyan("--healthDashboard.query.groq")}=<query> Custom GROQ query`),console.log(""),console.log(` ${l.bold("Examples:")}`),console.log(l.dim(" seofields config --baseUrl=https://example.com")),console.log(l.dim(" seofields config --healthDashboard.licenseKey=SEOF-777F-4C32-B154 --healthDashboard.showDocumentId=false")),console.log(l.dim(" seofields config --healthDashboard.query.types=post,page --seoPreview=true")),console.log("");}var qe=(e,t)=>`import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'
19
19
 
20
20
  export default defineSeoCli({
21
21
  projectId: '${e}',
@@ -35,33 +35,33 @@ export default defineSeoCli({
35
35
  // Document types that have SEO fields \u2014 used by \`report\` and \`export\`
36
36
  // types: ['post', 'page'],
37
37
  })
38
- `;function Be(e){var n,o;let t=T(e);if(!t)return {};try{let s=x.readFileSync(t,"utf-8"),i=(n=s.match(/projectId\s*:\s*['"`]([a-z0-9-]+)['"`]/))==null?void 0:n[1],r=(o=s.match(/dataset\s*:\s*['"`]([a-z0-9_-]+)['"`]/))==null?void 0:o[1];return {projectId:i,dataset:r}}catch(s){return {}}}async function ue(){var u,y,m,p;let e=process.cwd();$.intro(c.bold("seofields \u203A create-config"));let t=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(b=>x.existsSync(w.join(e,b)));if(t){let b=await $.confirm({message:`${c.yellow(t)} already exists. Overwrite?`,initialValue:false});($.isCancel(b)||!b)&&($.cancel("Aborted \u2014 existing config left untouched."),process.exit(0));}let n=Be(e),o=await $.select({message:"Which file format?",options:[{value:"ts",label:"TypeScript seofields.cli.ts (recommended)"},{value:"js",label:"JavaScript seofields.cli.js"}],initialValue:"ts"});$.isCancel(o)&&($.cancel("Cancelled."),process.exit(0));let s=await $.text({message:"Sanity Project ID",placeholder:(u=n.projectId)!=null?u:"abc123xyz",initialValue:(y=n.projectId)!=null?y:"",validate:b=>b.trim()?void 0:"Project ID is required"});$.isCancel(s)&&($.cancel("Cancelled."),process.exit(0));let i=await $.text({message:"Dataset name",placeholder:(m=n.dataset)!=null?m:"production",initialValue:(p=n.dataset)!=null?p:"production",validate:b=>b.trim()?void 0:"Dataset is required"});$.isCancel(i)&&($.cancel("Cancelled."),process.exit(0));let r=await $.select({message:"How will you provide the API token?",options:[{value:"env",label:`Environment variable ${c.dim("process.env.SANITY_TOKEN")} (recommended)`},{value:"none",label:"Skip \u2014 add manually later"}],initialValue:"env"});$.isCancel(r)&&($.cancel("Cancelled."),process.exit(0));let l=`seofields.cli.${o}`,d=w.join(e,l),f=(o==="ts"?qe:Je)(s,i);r==="none"&&(f=f.replace(` token: process.env.SANITY_TOKEN,
39
- `,"")),x.writeFileSync(d,f,"utf-8"),$.outro([c.green(`\u2714 Created ${l}`),"",c.dim(" Next steps:"),` ${c.dim("1.")} Add ${c.white("SANITY_TOKEN")} to your ${c.dim(".env")} file`,` ${c.dim("2.")} Run ${c.white("seofields report")} \u2014 no flags needed!`,` ${c.dim("3.")} Run ${c.white("seofields doctor")} to verify your setup`].join(`
40
- `));}async function ze(e){let t=[],o=["sanity.config.ts","sanity.config.js","sanity.config.mjs","sanity.config.tsx"].find(p=>x.existsSync(w.join(e,p)));t.push({name:"Sanity config file",ok:!!o,message:o?`Found ${o}`:`No sanity.config.ts/js found in ${e}`});let s=w.join(e,"package.json"),i=null;if(x.existsSync(s))try{i=JSON.parse(x.readFileSync(s,"utf-8"));}catch(p){}t.push({name:"package.json",ok:!!i,message:i?"Found package.json":"No package.json found"});let r=N(N({},i==null?void 0:i.dependencies),i==null?void 0:i.devDependencies),l=!!(r!=null&&r["sanity-plugin-seofields"]),d=r==null?void 0:r["sanity-plugin-seofields"];t.push({name:"Plugin installed",ok:l,message:l?`sanity-plugin-seofields@${d}`:"sanity-plugin-seofields not found in dependencies"});let g=[{name:"sanity",dep:"sanity",minMajor:3},{name:"react",dep:"react",minMajor:18}];for(let p of g){let b=r==null?void 0:r[p.dep],O=!!b;t.push({name:`Peer dep: ${p.name}`,ok:O,message:O?`${p.dep}@${b}`:`${p.dep} not found in dependencies`});}let f=w.join(e,"node_modules","sanity-plugin-seofields"),u=x.existsSync(f);t.push({name:"Plugin in node_modules",ok:u,message:u?"Plugin is installed in node_modules":"Plugin not found in node_modules \u2014 run npm install"}),o&&Xe(e,o,t),Ze(e,o,t);let m=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(p=>x.existsSync(w.join(e,p)));return t.push({name:"seofields.cli config",ok:!!m,message:m?`Found ${m} \u2014 project/dataset loaded automatically`:"No seofields.cli.ts found \u2014 create one with defineSeoCli() to skip --project-id flag"}),t}function Xe(e,t,n){let o=x.readFileSync(w.join(e,t),"utf-8"),s=o.includes("seofields(")||o.includes("seofields (");n.push({name:"Plugin registered",ok:s,message:s?"seofields() found in plugins array":"seofields() not found in config \u2014 run `seofields init`"});let i=o.includes("from 'sanity-plugin-seofields'")||o.includes('from "sanity-plugin-seofields"');n.push({name:"Import statement",ok:i,message:i?"import from 'sanity-plugin-seofields' found":"Missing import statement for sanity-plugin-seofields"});let r=Qe(e);n.push({name:"seoFields type usage",ok:r,message:r?"Found type: 'seoFields' in schema definitions":"No schema using type: 'seoFields' found \u2014 add it to a document type"});}function Qe(e){let t=w.join(e,"schemas"),n=w.join(e,"sanity","schemas"),o=w.join(e,"src","sanity","schemas"),s=[t,n,o];for(let i of s){if(!x.existsSync(i))continue;let r=pe(i);for(let l of r){if(!/\.(ts|tsx|js|jsx|mjs)$/.test(l))continue;let d=x.readFileSync(l,"utf-8");if(d.includes("type: 'seoFields'")||d.includes('type: "seoFields"'))return true}}return false}function Ze(e,t,n){let o=x.existsSync(w.join(e,".env"))||x.existsSync(w.join(e,".env.local"))||x.existsSync(w.join(e,".env.development")),s=!!(process.env.SANITY_PROJECT_ID||process.env.SANITY_STUDIO_PROJECT_ID),i=et(s,o,!!t);n.push({name:"Sanity env config",ok:o||s||!!t,message:i});}function et(e,t,n){return e?"SANITY_PROJECT_ID env var detected":t?".env file found":n?"Project config available from sanity.config":"No .env file or SANITY_PROJECT_ID env var found"}function tt(e){a.heading("");let t=e.filter(s=>s.ok).length,n=e.filter(s=>!s.ok).length;for(let s of e){let i=s.ok?c.green("\u2714"):c.red("\u2716"),r=s.ok?s.name:c.red(s.name);a.info(` ${i} ${r}`),a.dim(` ${s.message}`);}a.heading("");let o=n>0?`${c.green(`${t} passed`)}, ${c.red(`${n} failed`)}`:`${c.green(`${t} passed`)}, ${c.dim("0 failed")}`;a.info(` ${c.bold("Result:")} ${o}`);}async function ge(e){a.heading("seofields doctor"),a.heading("");let t=w.resolve(e.cwd),n=await ze(t);tt(n),n.filter(s=>!s.ok).length>0?(a.heading(""),a.dim(" Fix the issues above and run `seofields doctor` again."),process.exit(1)):(a.heading(""),a.success("Everything looks good! \u{1F389}"));}function pe(e){let t=[];try{let n=x.readdirSync(e,{withFileTypes:!0});for(let o of n){let s=w.join(e,o.name);o.name==="node_modules"||o.name===".git"||(o.isDirectory()?t.push(...pe(s)):t.push(s));}}catch(n){}return t}var nt=e=>e>=80?"excellent":e>=60?"good":e>=40?"fair":e>0?"poor":"missing",ot=e=>{let t=[],n=0;return e&&e.length>=50&&e.length<=60?n=15:e&&e.length>0?(n=10,e.length<50&&t.push("Meta title too short (< 50 chars)"),e.length>60&&t.push("Meta title too long (> 60 chars)")):t.push("Missing meta title"),{score:n,issues:t}},st=e=>{let t=[],n=0;return e&&e.length>=120&&e.length<=160?n=15:e&&e.length>0?(n=10,e.length<120&&t.push("Meta description too short (< 120 chars)"),e.length>160&&t.push("Meta description too long (> 160 chars)")):t.push("Missing meta description"),{score:n,issues:t}},it=e=>{let t=[],n=0;return e?(e.title?n+=6:t.push("Missing OG title"),e.description?n+=6:t.push("Missing OG description"),e.image?n+=6:t.push("Missing OG image"),e.type?n+=7:t.push("Missing OG type")):t.push("Open Graph not configured"),{score:n,issues:t}},rt=e=>{let t=[],n=0;return e?(e.title?n+=5:t.push("Missing Twitter title"),e.description?n+=5:t.push("Missing Twitter description"),e.image?n+=5:t.push("Missing Twitter image")):t.push("Twitter Card not configured"),{score:n,issues:t}},G=e=>{if(!e.seo)return {score:0,status:"missing",issues:["SEO fields not configured"]};let{title:t,description:n,keywords:o,robots:s,openGraph:i,twitter:r}=e.seo,l=0,d=[],g=ot(t);l+=g.score,d.push(...g.issues);let f=st(n);l+=f.score,d.push(...f.issues),e.seo.metaImage?l+=10:d.push("Missing meta image"),o&&o.length>0?l+=10:d.push("No keywords defined"),s&&!s.noIndex?l+=5:s||(l+=5);let u=it(i);l+=u.score,d.push(...u.issues);let y=rt(r);l+=y.score,d.push(...y.issues);let m=!!e.seo.metaImage,p=!!(i&&i.image),b=!!(r&&r.image);if(m&&p&&b)l+=5;else {let E=[];m||E.push("meta image"),p||E.push("OG image"),b||E.push("Twitter image"),d.push(`Missing images for full score: ${E.join(", ")}`);}let O=nt(l);return {score:l,status:O,issues:d}};async function me(e){var g;a.heading("seofields export");let t=await D();!e.types&&((g=t.types)!=null&&g.length)&&(e.types=t.types.join(","));let n=ct("Connecting to Sanity...").start(),o;try{({client:o}=await Y({projectId:e.projectId,dataset:e.dataset,token:e.token}));}catch(f){n.fail(f.message),process.exit(1);}let i=`*[${e.types?`_type in [${e.types.split(",").map(f=>`"${f.trim()}"`).join(", ")}] && `:""}defined(seo)]{
38
+ `;function Be(e){var n,o;let t=T(e);if(!t)return {};try{let s=I.readFileSync(t,"utf-8"),i=(n=s.match(/projectId\s*:\s*['"`]([a-z0-9-]+)['"`]/))==null?void 0:n[1],r=(o=s.match(/dataset\s*:\s*['"`]([a-z0-9_-]+)['"`]/))==null?void 0:o[1];return {projectId:i,dataset:r}}catch(s){return {}}}async function ue(){var g,S,m,p;let e=process.cwd();b.intro(l.bold("seofields \u203A create-config"));let t=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(y=>I.existsSync(C.join(e,y)));if(t){let y=await b.confirm({message:`${l.yellow(t)} already exists. Overwrite?`,initialValue:false});(b.isCancel(y)||!y)&&(b.cancel("Aborted \u2014 existing config left untouched."),process.exit(0));}let n=Be(e),o=await b.select({message:"Which file format?",options:[{value:"ts",label:"TypeScript seofields.cli.ts (recommended)"},{value:"js",label:"JavaScript seofields.cli.js"}],initialValue:"ts"});b.isCancel(o)&&(b.cancel("Cancelled."),process.exit(0));let s=await b.text({message:"Sanity Project ID",placeholder:(g=n.projectId)!=null?g:"abc123xyz",initialValue:(S=n.projectId)!=null?S:"",validate:y=>y!=null&&y.trim()?void 0:"Project ID is required"});b.isCancel(s)&&(b.cancel("Cancelled."),process.exit(0));let i=await b.text({message:"Dataset name",placeholder:(m=n.dataset)!=null?m:"production",initialValue:(p=n.dataset)!=null?p:"production",validate:y=>y!=null&&y.trim()?void 0:"Dataset is required"});b.isCancel(i)&&(b.cancel("Cancelled."),process.exit(0));let r=await b.select({message:"How will you provide the API token?",options:[{value:"env",label:`Environment variable ${l.dim("process.env.SANITY_TOKEN")} (recommended)`},{value:"none",label:"Skip \u2014 add manually later"}],initialValue:"env"});b.isCancel(r)&&(b.cancel("Cancelled."),process.exit(0));let d=`seofields.cli.${o}`,c=C.join(e,d),f=(o==="ts"?qe:Je)(s,i);r==="none"&&(f=f.replace(` token: process.env.SANITY_TOKEN,
39
+ `,"")),I.writeFileSync(c,f,"utf-8"),b.outro([l.green(`\u2714 Created ${d}`),"",l.dim(" Next steps:"),` ${l.dim("1.")} Add ${l.white("SANITY_TOKEN")} to your ${l.dim(".env")} file`,` ${l.dim("2.")} Run ${l.white("seofields report")} \u2014 no flags needed!`,` ${l.dim("3.")} Run ${l.white("seofields doctor")} to verify your setup`].join(`
40
+ `));}async function ze(e){let t=[],o=["sanity.config.ts","sanity.config.js","sanity.config.mjs","sanity.config.tsx"].find(p=>I.existsSync(C.join(e,p)));t.push({name:"Sanity config file",ok:!!o,message:o?`Found ${o}`:`No sanity.config.ts/js found in ${e}`});let s=C.join(e,"package.json"),i=null;if(I.existsSync(s))try{i=JSON.parse(I.readFileSync(s,"utf-8")),t.push({name:"package.json",ok:!0,message:"Found package.json"});}catch(p){return t.push({name:"package.json",ok:false,message:"package.json exists but contains invalid JSON \u2014 fix syntax and retry"}),t}else t.push({name:"package.json",ok:false,message:"No package.json found"});let r=N(N({},i==null?void 0:i.dependencies),i==null?void 0:i.devDependencies),d=!!(r!=null&&r["sanity-plugin-seofields"]),c=r==null?void 0:r["sanity-plugin-seofields"];t.push({name:"Plugin installed",ok:d,message:d?`sanity-plugin-seofields@${c}`:"sanity-plugin-seofields not found in dependencies"});let u=[{name:"sanity",dep:"sanity",minMajor:3},{name:"react",dep:"react",minMajor:18}];for(let p of u){let y=r==null?void 0:r[p.dep],j=!!y;t.push({name:`Peer dep: ${p.name}`,ok:j,message:j?`${p.dep}@${y}`:`${p.dep} not found in dependencies`});}let f=C.join(e,"node_modules","sanity-plugin-seofields"),g=I.existsSync(f);t.push({name:"Plugin in node_modules",ok:g,message:g?"Plugin is installed in node_modules":"Plugin not found in node_modules \u2014 run npm install"}),o&&Xe(e,o,t),Ze(e,o,t);let m=["seofields.cli.ts","seofields.cli.js","seofields.cli.mjs"].find(p=>I.existsSync(C.join(e,p)));return t.push({name:"seofields.cli config",ok:!!m,message:m?`Found ${m} \u2014 project/dataset loaded automatically`:"No seofields.cli.ts found \u2014 create one with defineSeoCli() to skip --project-id flag"}),t}function Xe(e,t,n){let o=I.readFileSync(C.join(e,t),"utf-8"),s=o.includes("seofields(")||o.includes("seofields (");n.push({name:"Plugin registered",ok:s,message:s?"seofields() found in plugins array":"seofields() not found in config \u2014 run `seofields init`"});let i=o.includes("from 'sanity-plugin-seofields'")||o.includes('from "sanity-plugin-seofields"');n.push({name:"Import statement",ok:i,message:i?"import from 'sanity-plugin-seofields' found":"Missing import statement for sanity-plugin-seofields"});let r=Qe(e);n.push({name:"seoFields type usage",ok:r,message:r?"Found type: 'seoFields' in schema definitions":"No schema using type: 'seoFields' found \u2014 add it to a document type"});}function Qe(e){let t=C.join(e,"schemas"),n=C.join(e,"sanity","schemas"),o=C.join(e,"src","sanity","schemas"),s=[t,n,o];for(let i of s){if(!I.existsSync(i))continue;let r=pe(i);for(let d of r){if(!/\.(ts|tsx|js|jsx|mjs)$/.test(d))continue;let c=I.readFileSync(d,"utf-8");if(c.includes("type: 'seoFields'")||c.includes('type: "seoFields"'))return true}}return false}function Ze(e,t,n){let o=I.existsSync(C.join(e,".env"))||I.existsSync(C.join(e,".env.local"))||I.existsSync(C.join(e,".env.development")),s=!!(process.env.SANITY_PROJECT_ID||process.env.SANITY_STUDIO_PROJECT_ID),i=et(s,o,!!t);n.push({name:"Sanity env config",ok:o||s||!!t,message:i});}function et(e,t,n){return e?"SANITY_PROJECT_ID env var detected":t?".env file found":n?"Project config available from sanity.config":"No .env file or SANITY_PROJECT_ID env var found"}function tt(e){a.heading("");let t=e.filter(s=>s.ok).length,n=e.filter(s=>!s.ok).length;for(let s of e){let i=s.ok?l.green("\u2714"):l.red("\u2716"),r=s.ok?s.name:l.red(s.name);a.info(` ${i} ${r}`),a.dim(` ${s.message}`);}a.heading("");let o=n>0?`${l.green(`${t} passed`)}, ${l.red(`${n} failed`)}`:`${l.green(`${t} passed`)}, ${l.dim("0 failed")}`;a.info(` ${l.bold("Result:")} ${o}`);}async function ge(e){a.heading("seofields doctor"),a.heading("");let t=C.resolve(e.cwd),n=await ze(t);tt(n),n.filter(s=>!s.ok).length>0?(a.heading(""),a.dim(" Fix the issues above and run `seofields doctor` again."),process.exit(1)):(a.heading(""),a.success("Everything looks good! \u{1F389}"));}function pe(e){let t=[];try{let n=I.readdirSync(e,{withFileTypes:!0});for(let o of n){let s=C.join(e,o.name);o.name==="node_modules"||o.name===".git"||(o.isDirectory()?t.push(...pe(s)):t.push(s));}}catch(n){}return t}var nt=e=>e>=80?"excellent":e>=60?"good":e>=40?"fair":e>0?"poor":"missing",ot=e=>{let t=[],n=0;return e&&e.length>=50&&e.length<=60?n=15:e&&e.length>0?(n=10,e.length<50&&t.push("Meta title too short (< 50 chars)"),e.length>60&&t.push("Meta title too long (> 60 chars)")):t.push("Missing meta title"),{score:n,issues:t}},st=e=>{let t=[],n=0;return e&&e.length>=120&&e.length<=160?n=15:e&&e.length>0?(n=10,e.length<120&&t.push("Meta description too short (< 120 chars)"),e.length>160&&t.push("Meta description too long (> 160 chars)")):t.push("Missing meta description"),{score:n,issues:t}},it=e=>{let t=[],n=0;return e?(e.title?n+=6:t.push("Missing OG title"),e.description?n+=6:t.push("Missing OG description"),e.image?n+=6:t.push("Missing OG image"),e.type?n+=7:t.push("Missing OG type")):t.push("Open Graph not configured"),{score:n,issues:t}},rt=e=>{let t=[],n=0;return e?(e.title?n+=5:t.push("Missing Twitter title"),e.description?n+=5:t.push("Missing Twitter description"),e.image?n+=5:t.push("Missing Twitter image")):t.push("Twitter Card not configured"),{score:n,issues:t}},K=e=>{if(!e.seo)return {score:0,status:"missing",issues:["SEO fields not configured"]};let t=e.seo,n=t.title,o=t.description,s=t.keywords,i=t.robots,r=t.openGraph,d=t.twitter,c=0,u=[],f=ot(n);c+=f.score,u.push(...f.issues);let g=st(o);c+=g.score,u.push(...g.issues),t.metaImage?c+=10:u.push("Missing meta image"),s&&s.length>0?c+=10:u.push("No keywords defined"),i&&!i.noIndex?c+=5:i||(c+=5);let S=it(r);c+=S.score,u.push(...S.issues);let m=rt(d);c+=m.score,u.push(...m.issues);let p=!!t.metaImage,y=!!(r&&r.image),j=!!(d&&d.image);if(p&&y&&j)c+=5;else {let E=[];p||E.push("meta image"),y||E.push("OG image"),j||E.push("Twitter image"),u.push(`Missing images for full score: ${E.join(", ")}`);}let U=nt(c);return {score:c,status:U,issues:u}};async function me(e){var u;a.heading("seofields export");let t=await D();!e.types&&((u=t.types)!=null&&u.length)&&(e.types=t.types.join(","));let n=ct("Connecting to Sanity...").start(),o;try{({client:o}=await G({projectId:e.projectId,dataset:e.dataset,token:e.token}));}catch(f){n.fail(f.message),process.exit(1);}let i=`*[${e.types?`_type in [${e.types.split(",").map(f=>`"${f.trim()}"`).join(", ")}] && `:""}defined(seo)]{
41
41
  _id,
42
42
  _type,
43
43
  _updatedAt,
44
44
  title,
45
45
  slug,
46
46
  seo
47
- } | order(_updatedAt desc)`;n.text="Fetching documents...";let r;try{r=await o.fetch(i);}catch(f){n.fail(`Failed to fetch documents: ${f.message}`),process.exit(1);}if(n.succeed(`Found ${r.length} document(s) with SEO fields`),r.length===0){a.warn("No documents found. Check your project ID, dataset, and API token permissions.");return}let l=r.map(f=>{var y,m,p,b,O,E,Z;let u=G(f);return {_id:f._id,_type:f._type,title:f.title||"",slug:((y=f.slug)==null?void 0:y.current)||"",seoScore:u.score,seoStatus:u.status,issues:u.issues,seoTitle:((m=f.seo)==null?void 0:m.title)||"",seoDescription:((p=f.seo)==null?void 0:p.description)||"",hasKeywords:Array.isArray((b=f.seo)==null?void 0:b.keywords)&&f.seo.keywords.length>0,hasOpenGraph:!!((O=f.seo)!=null&&O.openGraph),hasTwitter:!!((E=f.seo)!=null&&E.twitter),hasMetaImage:!!((Z=f.seo)!=null&&Z.metaImage),_updatedAt:f._updatedAt||""}}),d;if(e.format==="csv"){let f=["_id","_type","title","slug","seoScore","seoStatus","issues","seoTitle","seoDescription","hasKeywords","hasOpenGraph","hasTwitter","hasMetaImage","_updatedAt"],u=[f.join(",")];for(let y of l)u.push(f.map(m=>{let p=y[m];return Array.isArray(p)?`"${p.join("; ").replace(/"/g,'""')}"`:typeof p=="string"?`"${p.replace(/"/g,'""')}"`:String(p)}).join(","));d=u.join(`
48
- `);}else d=JSON.stringify(l,null,2);e.output?(x.writeFileSync(e.output,d,"utf-8"),a.success(`Exported to ${e.output}`)):console.log(d);}function lt(){process.argv.includes("--dashboard")&&process.argv.includes("--no-dashboard")&&(a.error("Conflicting flags: --dashboard and --no-dashboard cannot be used together."),process.exit(1));}function dt(e){let t=[];return e.preview&&t.push("seoPreview: true"),e.dashboard===true&&t.push("healthDashboard: true"),e.dashboard===false&&t.push("healthDashboard: false"),t.length>0?`seofields({ ${t.join(", ")} })`:"seofields()"}function he(e,t,n,o){let s=[t?"":"import seofields from 'sanity-plugin-seofields'",o&&!n?"import {schemaOrg} from 'sanity-plugin-seofields/schema'":""].filter(Boolean).join(`
47
+ } | order(_updatedAt desc)`;n.text="Fetching documents...";let r;try{r=await o.fetch(i);}catch(f){n.fail(`Failed to fetch documents: ${f.message}`),process.exit(1);}if(n.succeed(`Found ${r.length} document(s) with SEO fields`),r.length===0){a.warn("No documents found. Check your project ID, dataset, and API token permissions.");return}let d=r.map(f=>{var S,m,p,y,j,U,E;let g=K(f);return {_id:f._id,_type:f._type,title:f.title||"",slug:((S=f.slug)==null?void 0:S.current)||"",seoScore:g.score,seoStatus:g.status,issues:g.issues,seoTitle:((m=f.seo)==null?void 0:m.title)||"",seoDescription:((p=f.seo)==null?void 0:p.description)||"",hasKeywords:Array.isArray((y=f.seo)==null?void 0:y.keywords)&&f.seo.keywords.length>0,hasOpenGraph:!!((j=f.seo)!=null&&j.openGraph),hasTwitter:!!((U=f.seo)!=null&&U.twitter),hasMetaImage:!!((E=f.seo)!=null&&E.metaImage),_updatedAt:f._updatedAt||""}}),c;if(e.format==="csv"){let f=["_id","_type","title","slug","seoScore","seoStatus","issues","seoTitle","seoDescription","hasKeywords","hasOpenGraph","hasTwitter","hasMetaImage","_updatedAt"],g=[f.join(",")];for(let S of d)g.push(f.map(m=>{let p=S[m];return Array.isArray(p)?`"${p.join("; ").replace(/"/g,'""')}"`:typeof p=="string"?`"${p.replace(/"/g,'""')}"`:String(p)}).join(","));c=g.join(`
48
+ `);}else c=JSON.stringify(d,null,2);e.output?(I.writeFileSync(e.output,c,"utf-8"),a.success(`Exported to ${e.output}`)):console.log(c);}function lt(){process.argv.includes("--dashboard")&&process.argv.includes("--no-dashboard")&&(a.error("Conflicting flags: --dashboard and --no-dashboard cannot be used together."),process.exit(1));}function dt(e){let t=[];return e.preview&&t.push("seoPreview: true"),e.dashboard===true&&t.push("healthDashboard: true"),e.dashboard===false&&t.push("healthDashboard: false"),t.length>0?`seofields({ ${t.join(", ")} })`:"seofields()"}function he(e,t,n,o){let s=[t?"":"import seofields from 'sanity-plugin-seofields'",o&&!n?"import {schemaOrg} from 'sanity-plugin-seofields/schema'":""].filter(Boolean).join(`
49
49
  `);if(!s)return e;let i=[...e.matchAll(/^import\s.+$/gm)].at(-1),r=i?i.index+i[0].length:0;return r>0?`${e.slice(0,r)}
50
50
  ${s}${e.slice(r)}`:`${s}
51
51
 
52
52
  ${e}`}function ft(e,t,n,o){a.success(`Updated ${e}`),a.dim(""),a.dim(" What was added:"),a.dim(" import seofields from 'sanity-plugin-seofields'"),o&&a.dim(" import {schemaOrg} from 'sanity-plugin-seofields/schema'"),a.dim(` plugins: [${t}${n}, ...]`),a.dim(""),a.dim(" Next steps:"),a.dim(" 1. Add the seo field to your document schemas:"),a.dim(" defineField({ name: 'seo', title: 'SEO', type: 'seoFields' })"),a.dim(" 2. Restart Sanity Studio");}async function ye(e){a.heading("seofields init"),lt();let t=T(process.cwd());t||(a.error(`No sanity.config.ts/js found in current directory.
53
- Run this command from your Sanity project root.`),process.exit(1)),a.info(`Found config: ${t}`);let n=x.readFileSync(t,"utf-8"),o=/from\s+['"]sanity-plugin-seofields['"]/.test(n),s=/from\s+['"]sanity-plugin-seofields\/schema['"]/.test(n),i=/plugins\s*:\s*\[[\s\S]*?\bseofields\s*\(/.test(n),r=/plugins\s*:\s*\[[\s\S]*?\bschemaOrg\s*\(/.test(n);if(i){let f=e.schemaOrg&&(!s||!r),u=!o;if(!f&&!u){a.warn("seofields() is already registered in your config."),a.dim(" No changes made.");return}if(n=he(n,o,s,!!e.schemaOrg),e.schemaOrg&&!r){let y=/plugins\s*:\s*\[/.exec(n);if(y){let m=y.index+y[0].length;n=`${n.slice(0,m)}
54
- schemaOrg(),${n.slice(m)}`,a.success("Added schemaOrg() to plugins array");}}x.writeFileSync(t,n,"utf-8"),u&&a.success("Added missing import for seofields"),e.schemaOrg&&!s&&a.dim(" Added: import {schemaOrg} from 'sanity-plugin-seofields/schema'"),a.success(`Updated ${t}`);return}let l=dt(e),d=e.schemaOrg&&!r?", schemaOrg()":"";n=he(n,o,s,!!e.schemaOrg);let g=/plugins\s*:\s*\[/.exec(n);if(g){let f=g.index+g[0].length;n=`${n.slice(0,f)}
55
- ${l}${d},${n.slice(f)}`,a.success("Added seofields() to plugins array"),d&&a.success("Added schemaOrg() to plugins array"),e.schemaOrg&&r&&a.dim(" schemaOrg() already in plugins \u2014 import added only");}else a.warn(`Could not find \`plugins: [...]\` in your config.
53
+ Run this command from your Sanity project root.`),process.exit(1)),a.info(`Found config: ${t}`);let n=I.readFileSync(t,"utf-8"),o=/from\s+['"]sanity-plugin-seofields['"]/.test(n),s=/from\s+['"]sanity-plugin-seofields\/schema['"]/.test(n),i=/plugins\s*:\s*\[[\s\S]*?\bseofields\s*\(/.test(n),r=/plugins\s*:\s*\[[\s\S]*?\bschemaOrg\s*\(/.test(n);if(i){let f=e.schemaOrg&&(!s||!r),g=!o;if(!f&&!g){a.warn("seofields() is already registered in your config."),a.dim(" No changes made.");return}if(n=he(n,o,s,!!e.schemaOrg),e.schemaOrg&&!r){let S=/plugins\s*:\s*\[/.exec(n);if(S){let m=S.index+S[0].length;n=`${n.slice(0,m)}
54
+ schemaOrg(),${n.slice(m)}`,a.success("Added schemaOrg() to plugins array");}}I.writeFileSync(t,n,"utf-8"),g&&a.success("Added missing import for seofields"),e.schemaOrg&&!s&&a.dim(" Added: import {schemaOrg} from 'sanity-plugin-seofields/schema'"),a.success(`Updated ${t}`);return}let d=dt(e),c=e.schemaOrg&&!r?", schemaOrg()":"";n=he(n,o,s,!!e.schemaOrg);let u=/plugins\s*:\s*\[/.exec(n);if(u){let f=u.index+u[0].length;n=`${n.slice(0,f)}
55
+ ${d}${c},${n.slice(f)}`,a.success("Added seofields() to plugins array"),c&&a.success("Added schemaOrg() to plugins array"),e.schemaOrg&&r&&a.dim(" schemaOrg() already in plugins \u2014 import added only");}else a.warn(`Could not find \`plugins: [...]\` in your config.
56
56
  Please add manually:
57
- plugins: [${l}${d}]`);x.writeFileSync(t,n,"utf-8"),ft(t,l,d,!!e.schemaOrg);}async function be(e){var f;a.heading("seofields report");let t=await D();!e.types&&((f=t.types)!=null&&f.length)&&(e.types=t.types.join(","));let n=t.showConnectionInfo===true,o=ct("Connecting to Sanity...").start(),s,i;try{({client:s,resolved:i}=await Y({projectId:e.projectId,dataset:e.dataset,token:e.token}));}catch(u){o.fail(u.message),process.exit(1);}let l=`*[${e.types?`_type in [${e.types.split(",").map(u=>`"${u.trim()}"`).join(", ")}] && `:""}defined(seo)]{
57
+ plugins: [${d}${c}]`);I.writeFileSync(t,n,"utf-8"),ft(t,d,c,!!e.schemaOrg);}async function be(e){var f;a.heading("seofields report");let t=await D();!e.types&&((f=t.types)!=null&&f.length)&&(e.types=t.types.join(","));let n=t.showConnectionInfo===true,o=ct("Connecting to Sanity...").start(),s,i;try{({client:s,resolved:i}=await G({projectId:e.projectId,dataset:e.dataset,token:e.token}));}catch(g){o.fail(g.message),process.exit(1);}let d=`*[${e.types?`_type in [${e.types.split(",").map(g=>`"${g.trim()}"`).join(", ")}] && `:""}defined(seo)]{
58
58
  _id,
59
59
  _type,
60
60
  _updatedAt,
61
61
  title,
62
62
  slug,
63
63
  seo
64
- } | order(_updatedAt desc)`;o.text="Fetching documents...";let d;try{d=await s.fetch(l);}catch(u){o.fail(`Failed to fetch: ${u.message}`),process.exit(1);}if(o.succeed(`Analysed ${d.length} document(s)`),d.length===0){a.warn("No documents with SEO fields found."),n&&Se(i);return}let g=d.map(u=>({doc:u,health:G(u)}));await gt(g,d,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:d}of e)o[d.status]=(o[d.status]||0)+1,s+=d.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:d}of e)for(let g of d.issues)r[g]=(r[g]||0)+1;let l=Object.entries(r).sort(([,d],[,g])=>g-d).slice(0,10);l.length>0&&$t(l,t.length),a.info("");}function pt(e,t,n){a.heading("\u{1F4CA} Summary"),a.info(""),a.info(` Total documents: ${c.bold(String(e.length))}`),a.info(` Average score: ${c.bold(ve(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:c.green,good:c.blue,fair:c.yellow,poor:c.red,missing:c.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=c.dim("\u2500".repeat(s+2+n+2+o+2+t));a.info(` ${c.dim("Score".padEnd(s))} ${c.dim("Status".padEnd(n))} ${c.dim("Type".padEnd(o))} ${c.dim("Title")}`),a.info(` ${i}`);for(let{doc:r,health:l}of e){let d=$e(r.title||r._id,t),g=String(l.score).padStart(s),f=yt(l.status,n),u=c.dim($e(r._type,o).padEnd(o));a.info(` ${ve(l.score,g)} ${f} ${u} ${d}`);}}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(` ${c.red(String(o).padStart(4))} docs (${s}%) ${n}`);}}function Se(e){a.info(""),a.info(` ${c.dim("\u2500".repeat(52))}`),a.info(` ${c.dim("Connection info")}`),a.info(` ${c.dim("Project ID:")} ${c.white(e.projectId)} ${c.dim(`\u2190 ${e.sources.projectId}`)}`),a.info(` ${c.dim("Dataset: ")} ${c.white(e.dataset)} ${c.dim(`\u2190 ${e.sources.dataset}`)}`),a.info(` ${c.dim("Token: ")} ${c.dim(e.sources.token)}`),a.info("");}function ve(e,t){let n=t!=null?t:String(e);return e>=80?c.green(n):e>=60?c.blue(n):e>=40?c.yellow(n):e>0?c.red(n):c.dim(n)}function $e(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e}U();var Q="1.5.4",Ce=[c.cyan,e=>c.bold(c.blue(e)),c.blue,c.magenta,c.red,c.yellow],v=Ce[Math.floor(Math.random()*Ce.length)],we=["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 we[Math.floor(Math.random()*we.length)]}var vt=62,K=vt-2;function Ct(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=K-3,o=" ".repeat(Math.max(0,n-t));return ` ${v("\u2502")} ${e}${o} ${v("\u2502")}`}function M(){return F("",0)}function Ie(){let e="\u2500".repeat(K),t=bt(),n=K-3-5,o=Ct(t,n);console.log(),console.log(` ${v(`\u256D${e}\u256E`)}`),console.log(M()),console.log(F(`${c.bold(c.green("seofields"))}${c.dim(` v${Q}`)}`,`seofields v${Q}`.length)),console.log(F(c.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?`${c.dim("Tip: ")}${c.white(o[i])}`:` ${c.white(o[i])}`,l=5+o[i].length;console.log(F(r,l));}console.log(M()),console.log(` ${v(`\u2570${e}\u256F`)}`),console.log(),console.log(` ${c.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(` ${v(i)} ${c.dim(r)}`);console.log(),console.log(` ${c.dim("Run ")}${c.white("seofields <command> --help")}${c.dim(" for details")}`),console.log();}function P(e,t){let n="\u2500".repeat(K),o=`seofields \u203A ${e}`;return ["",` ${v(`\u256D${n}\u256E`)}`,M(),F(`${c.bold(c.green("seofields"))}${v(" \u203A ")}${c.bold(v(e))}`,o.length),F(c.dim(t),t.length),M(),` ${v(`\u2570${n}\u256F`)}`].join(`
65
- `)}program.name("seofields").description("CLI for sanity-plugin-seofields \u2014 manage SEO from your terminal").version(Q).action(Ie);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",["",` ${c.bold("Usage")}`,` ${c.dim("Pass any option as")} ${c.white("--key=value")}${c.dim(". Nested keys use dot notation.")}`,"",` ${c.bold("Top-level options")}`,` ${v("--baseUrl")}${c.dim("=<url>").padEnd(38)} ${c.dim("Canonical base URL")}`,` ${v("--seoPreview")}${c.dim("=<bool>").padEnd(36)} ${c.dim("Enable live Google-style preview")}`,` ${v("--defaultHiddenFields")}${c.dim("=<f1,f2>").padEnd(28)} ${c.dim("Comma-separated fields to hide")}`,` ${v("--types")}${c.dim("=<t1,t2>").padEnd(40)} ${c.dim("Document types that have SEO fields")}`,"",` ${c.bold("healthDashboard options")} ${c.dim("(prefix: --healthDashboard.<key>)")}`,` ${v("--healthDashboard.licenseKey")}${c.dim("=<key>").padEnd(22)} ${c.dim("License key for premium features")}`,` ${v("--healthDashboard.toolTitle")}${c.dim("=<str>").padEnd(23)} ${c.dim("Custom title shown in Studio")}`,` ${v("--healthDashboard.showDocumentId")}${c.dim("=<bool>").padEnd(17)} ${c.dim("Show document _id in dashboard")}`,` ${v("--healthDashboard.showHealthScore")}${c.dim("=<bool>").padEnd(16)} ${c.dim("Show score badge per document")}`,` ${v("--healthDashboard.query.types")}${c.dim("=<t1,t2>").padEnd(21)} ${c.dim("Filter dashboard by document types")}`,"",` ${c.bold("Examples")}`,` ${c.white("seofields config --baseUrl=https://mysite.com")}`,` ${c.white("seofields config --healthDashboard.licenseKey=SEOF-1234")}`,` ${c.white("seofields config --healthDashboard.showDocumentId=true --seoPreview=true")}`,` ${c.white("seofields config --healthDashboard.query.types=post,page")}`,` ${c.white("seofields config --defaultHiddenFields=metaImage,openGraphUrl")}`,""].join(`
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",["",` ${c.dim("Note: ")}${c.yellow("--preview")}${c.dim(", ")}${c.yellow("--dashboard")}${c.dim(", and ")}${c.yellow("--no-dashboard")}${c.dim(" only apply during initial setup.")}`,` ${c.dim(" If seofields() is already in your config, use:")}`,"",` ${c.dim(" ")}${c.white("seofields config --healthDashboard=true --seoPreview=true")}`,""].join(`
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")&&(Ie(),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();
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(`
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
+ `)).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
+ `)).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();