sanity-plugin-seofields 1.4.1 → 1.5.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 (57) hide show
  1. package/README.md +1 -1
  2. package/dist/SeoHealthDashboard-3VBITMWT.cjs +10 -0
  3. package/dist/SeoHealthDashboard-3VBITMWT.cjs.map +1 -0
  4. package/dist/SeoHealthDashboard-BNJBRQVN.js +4 -0
  5. package/dist/SeoHealthDashboard-BNJBRQVN.js.map +1 -0
  6. package/dist/SeoHealthTool-4P6JST5S.cjs +14 -0
  7. package/dist/SeoHealthTool-4P6JST5S.cjs.map +1 -0
  8. package/dist/SeoHealthTool-MQBE5YGN.js +12 -0
  9. package/dist/SeoHealthTool-MQBE5YGN.js.map +1 -0
  10. package/dist/SeoPreview-G3LPA7GV.js +148 -0
  11. package/dist/SeoPreview-G3LPA7GV.js.map +1 -0
  12. package/dist/SeoPreview-Y3CFDVBR.cjs +154 -0
  13. package/dist/SeoPreview-Y3CFDVBR.cjs.map +1 -0
  14. package/dist/chunk-25JLWVEU.js +472 -0
  15. package/dist/chunk-25JLWVEU.js.map +1 -0
  16. package/dist/chunk-2NMEKWO5.js +35 -0
  17. package/dist/chunk-2NMEKWO5.js.map +1 -0
  18. package/dist/chunk-527WXITP.js +428 -0
  19. package/dist/chunk-527WXITP.js.map +1 -0
  20. package/dist/chunk-6CYMVS3O.js +1245 -0
  21. package/dist/chunk-6CYMVS3O.js.map +1 -0
  22. package/dist/chunk-D2GWRRK5.cjs +1293 -0
  23. package/dist/chunk-D2GWRRK5.cjs.map +1 -0
  24. package/dist/chunk-DYVCCQHT.cjs +1400 -0
  25. package/dist/chunk-DYVCCQHT.cjs.map +1 -0
  26. package/dist/chunk-IFDLKZET.cjs +485 -0
  27. package/dist/chunk-IFDLKZET.cjs.map +1 -0
  28. package/dist/chunk-L3L3FSPJ.cjs +478 -0
  29. package/dist/chunk-L3L3FSPJ.cjs.map +1 -0
  30. package/dist/chunk-S367Y35J.cjs +39 -0
  31. package/dist/chunk-S367Y35J.cjs.map +1 -0
  32. package/dist/chunk-WUIZN7VI.js +1394 -0
  33. package/dist/chunk-WUIZN7VI.js.map +1 -0
  34. package/dist/cli.js +67 -0
  35. package/dist/define-cli.cjs +12 -0
  36. package/dist/define-cli.cjs.map +1 -0
  37. package/dist/define-cli.d.cts +42 -0
  38. package/dist/define-cli.d.ts +42 -0
  39. package/dist/define-cli.js +10 -0
  40. package/dist/define-cli.js.map +1 -0
  41. package/dist/index.cjs +154 -2365
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/index.js +109 -2303
  44. package/dist/index.js.map +1 -1
  45. package/dist/next.cjs +235 -1591
  46. package/dist/next.cjs.map +1 -1
  47. package/dist/next.js +7 -1482
  48. package/dist/next.js.map +1 -1
  49. package/dist/schema/next.cjs +200 -1542
  50. package/dist/schema/next.cjs.map +1 -1
  51. package/dist/schema/next.js +4 -1475
  52. package/dist/schema/next.js.map +1 -1
  53. package/dist/schema.cjs +252 -1514
  54. package/dist/schema.cjs.map +1 -1
  55. package/dist/schema.js +58 -1391
  56. package/dist/schema.js.map +1 -1
  57. package/package.json +21 -5
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/SeoHealthDashboard.tsx"],"names":[],"mappings":"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","file":"chunk-WUIZN7VI.js","sourcesContent":["import React, {useCallback, useEffect, useMemo, useState} from 'react'\nimport {useClient, useWorkspace} from 'sanity'\nimport {useIntentLink} from 'sanity/router'\nimport {usePaneRouter} from 'sanity/structure'\nimport styled, {css, keyframes} from 'styled-components'\n\nimport {DeprecationWarning, DocumentWithSeoHealth, SeoHealthMetrics} from '../types'\n\nconst DashboardContainer = styled.div`\n width: 100%;\n min-height: 100%;\n background: #f0f2f5;\n padding: 28px 32px;\n box-sizing: border-box;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n`\n\nconst PageHeader = styled.div`\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 28px;\n`\n\nconst PageTitle = styled.h1`\n margin: 0 0 6px 0;\n font-size: 22px;\n font-weight: 700;\n color: #111827;\n letter-spacing: -0.3px;\n display: flex;\n align-items: center;\n gap: 10px;\n`\n\nconst PreviewBadge = styled.span`\n display: inline-block;\n background: #fef3c7;\n color: #92400e;\n font-size: 11px;\n font-weight: 600;\n padding: 4px 8px;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-left: 8px;\n`\n\nconst PageSubtitle = styled.p`\n margin: 0;\n font-size: 13px;\n color: #6b7280;\n`\n\nconst StatsGrid = styled.div`\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));\n gap: 14px;\n margin-bottom: 20px;\n`\n\nconst StatCard = styled.div<{$accent?: string}>`\n background: #ffffff;\n border-radius: 10px;\n padding: 16px 18px;\n box-shadow:\n 0 1px 3px rgba(0, 0, 0, 0.07),\n 0 1px 2px rgba(0, 0, 0, 0.05);\n border-left: ${(p) => (p.$accent ? `4px solid ${p.$accent}` : '4px solid transparent')};\n transition: box-shadow 0.15s ease;\n\n &:hover {\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n }\n`\n\nconst StatLabel = styled.div`\n font-size: 11px;\n font-weight: 500;\n color: #9ca3af;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n`\n\nconst StatValue = styled.div`\n font-size: 26px;\n font-weight: 700;\n color: #111827;\n line-height: 1;\n`\n\nconst ControlsBar = styled.div`\n background: #ffffff;\n border-radius: 10px;\n padding: 14px 18px;\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n margin-bottom: 20px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n`\n\nconst SearchWrapper = styled.div`\n position: relative;\n flex: 1;\n min-width: 220px;\n`\n\nconst SearchIconSvg = styled.span`\n position: absolute;\n left: 11px;\n top: 50%;\n transform: translateY(-50%);\n color: #9ca3af;\n display: flex;\n align-items: center;\n pointer-events: none;\n`\n\nconst SearchInput = styled.input`\n width: 100%;\n height: 36px;\n padding: 0 12px 0 34px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #111827;\n background: #f9fafb;\n box-sizing: border-box;\n outline: none;\n transition:\n border-color 0.15s,\n background 0.15s;\n\n &::placeholder {\n color: #9ca3af;\n }\n\n &:focus {\n border-color: #6366f1;\n background: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst StyledSelect = styled.select`\n height: 36px;\n padding: 0 32px 0 12px;\n border: 1px solid #e5e7eb;\n border-radius: 7px;\n font-size: 13px;\n color: #374151;\n background: #f9fafb\n url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E\")\n no-repeat right 10px center;\n appearance: none;\n outline: none;\n cursor: pointer;\n transition: border-color 0.15s;\n\n &:focus {\n border-color: #6366f1;\n background-color: #fff;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n`\n\nconst TableCard = styled.div`\n background: #ffffff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.07);\n overflow: hidden;\n`\n\nconst TableHeader = styled.div`\n display: flex;\n align-items: center;\n padding: 11px 20px;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n font-size: 11px;\n font-weight: 600;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n gap: 12px;\n`\n\nconst TableRow = styled.div`\n display: flex;\n align-items: center;\n padding: 13px 20px;\n border-bottom: 1px solid #f3f4f6;\n gap: 12px;\n transition: background 0.1s;\n\n &:last-child {\n border-bottom: none;\n }\n\n &:hover {\n background: #fafafa;\n }\n`\n\nconst ColTitle = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst TitleWrapper = styled.div`\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n min-width: 0;\n`\n\n/* Constrains the title + doc-id block so text-overflow works inside flex */\nconst TitleCell = styled.div`\n min-width: 0;\n overflow: hidden;\n flex: 1;\n`\n\nconst ColType = styled.div`\n flex: 0.8;\n min-width: 80px;\n`\n\nconst ColScore = styled.div`\n flex: 0.6;\n min-width: 70px;\n`\n\nconst ColIssues = styled.div`\n flex: 2;\n min-width: 0;\n`\n\nconst DocTitleLink = styled.a`\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n`\n\nconst DocId = styled.div`\n font-size: 11px;\n color: #9ca3af;\n margin-top: 2px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst TypeBadge = styled.span<{$bgColor?: string; $textColor?: string}>`\n display: inline-block;\n padding: 3px 8px;\n border-radius: 5px;\n font-size: 11px;\n font-weight: 500;\n background: ${(p) => p.$bgColor || '#ede9fe'};\n color: ${(p) => p.$textColor || '#5b21b6'};\n`\n\nconst TypeText = styled.span`\n font-size: 12px;\n font-weight: 500;\n color: #374151;\n`\n\nconst CustomBadge = styled.span<{$bgColor?: string; $textColor?: string; $fontSize?: string}>`\n display: inline-block;\n padding: 2px 6px;\n border-radius: 4px;\n font-size: ${(p) => p.$fontSize || '10px'};\n font-weight: 600;\n background: ${(p) => p.$bgColor || '#e0e7ff'};\n color: ${(p) => p.$textColor || '#3730a3'};\n white-space: nowrap;\n`\n\nconst ScoreBadge = styled.span<{$score: number}>`\n display: inline-block;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 700;\n background: ${(p) => {\n if (p.$score >= 80) return '#d1fae5'\n if (p.$score >= 60) return '#fef3c7'\n if (p.$score >= 40) return '#ffedd5'\n return '#fee2e2'\n }};\n color: ${(p) => {\n if (p.$score >= 80) return '#065f46'\n if (p.$score >= 60) return '#92400e'\n if (p.$score >= 40) return '#9a3412'\n return '#991b1b'\n }};\n`\n\nconst IssueTag = styled.div`\n font-size: 11px;\n color: #ef4444;\n line-height: 1.5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`\n\nconst NonStringTitleWarning = styled.div`\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 2px 7px;\n border-radius: 4px;\n background: #fef3c7;\n border: 1px solid #fcd34d;\n font-size: 10px;\n font-weight: 600;\n color: #92400e;\n line-height: 1.4;\n cursor: default;\n white-space: normal;\n`\n\nconst MoreIssues = styled.div`\n font-size: 11px;\n color: #6b7280;\n cursor: pointer;\n transition: color 0.15s;\n\n &:hover {\n color: #374151;\n }\n`\n\nconst MoreIssuesWrapper = styled.div`\n position: relative;\n display: inline-block;\n`\n\nconst IssuesPopover = styled.div<{\n $left?: number\n}>`\n position: fixed;\n bottom: auto;\n left: 0;\n transform: translateY(calc(-100% - 14px));\n background: #1f2937;\n color: #ffffff;\n padding: 12px;\n border-radius: 8px;\n font-size: 12px;\n z-index: 50;\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);\n width: 280px;\n word-break: break-word;\n line-height: 1.5;\n\n &::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 12px;\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid #1f2937;\n }\n`\n\nconst PopoverIssueItem = styled.div`\n display: flex;\n gap: 6px;\n margin-bottom: 6px;\n\n &:last-child {\n margin-bottom: 0;\n }\n`\n\nconst UpgradeContainer = styled.div`\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100%;\n padding: 60px 24px;\n`\n\nconst UpgradeBox = styled.div`\n background: #ffffff;\n border-radius: 16px;\n padding: 48px 40px;\n max-width: 480px;\n width: 100%;\n text-align: center;\n box-shadow:\n 0 4px 24px rgba(0, 0, 0, 0.08),\n 0 1px 4px rgba(0, 0, 0, 0.05);\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeLock = styled.div`\n font-size: 40px;\n margin-bottom: 16px;\n`\n\nconst UpgradeTitle = styled.h2`\n margin: 0 0 10px;\n font-size: 20px;\n font-weight: 700;\n color: #111827;\n`\n\nconst UpgradeText = styled.p`\n margin: 0 0 20px;\n font-size: 14px;\n color: #6b7280;\n line-height: 1.6;\n`\n\nconst UpgradeCode = styled.pre`\n background: #f3f4f6;\n border-radius: 8px;\n padding: 14px 16px;\n font-size: 12px;\n color: #374151;\n text-align: left;\n margin: 0 0 24px;\n overflow-x: auto;\n line-height: 1.6;\n border: 1px solid #e5e7eb;\n`\n\nconst UpgradeButton = styled.a`\n display: inline-block;\n background: #4f46e5;\n color: #ffffff;\n font-size: 14px;\n font-weight: 600;\n padding: 10px 24px;\n border-radius: 8px;\n text-decoration: none;\n transition: background 0.15s;\n\n &:hover {\n background: #4338ca;\n }\n`\n\nconst ReloadButton = styled.button`\n display: inline-block;\n background: transparent;\n color: #6b7280;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 20px;\n border-radius: 8px;\n border: 1px solid #d1d5db;\n cursor: pointer;\n margin-top: 10px;\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s;\n\n &:hover {\n background: #f3f4f6;\n color: #374151;\n border-color: #9ca3af;\n }\n`\n\nconst spin = keyframes`\n to { transform: rotate(360deg); }\n`\n\nconst DashboardRefreshButton = styled.button<{$spinning?: boolean}>`\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: #ffffff;\n color: #374151;\n font-size: 13px;\n font-weight: 500;\n padding: 8px 14px;\n border-radius: 8px;\n border: 1px solid #d1d5db;\n cursor: pointer;\n flex-shrink: 0;\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s,\n box-shadow 0.15s;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n\n svg {\n animation: ${(p) =>\n p.$spinning\n ? css`\n ${spin} 0.7s linear infinite\n `\n : 'none'};\n }\n\n &:hover {\n background: #f3f4f6;\n border-color: #9ca3af;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n }\n\n &:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n`\n\n// Sub-component so useIntentLink can be called at the top level of a component (not inside .map)\nconst DocTitleAnchor: React.FC<{\n id: string\n type: string\n structureTool?: string\n children: React.ReactNode\n}> = ({id, type, structureTool, children}) => {\n const {basePath} = useWorkspace()\n const {onClick: intentOnClick, href: intentHref} = useIntentLink({\n intent: 'edit',\n params: {id, type},\n })\n // When a specific structure tool name is provided, build a tool-scoped intent URL so that\n // Sanity routes directly to that tool instead of letting the router pick the first match.\n const href = structureTool\n ? `${basePath}/${structureTool}/intent/edit/id=${id};type=${type}/`\n : intentHref\n const onClick = structureTool ? undefined : intentOnClick\n return (\n <DocTitleLink href={href} onClick={onClick} title=\"Open document\">\n {children}\n </DocTitleLink>\n )\n}\n\n// Wrapper that applies DocTitleLink styles to the ChildLink <a> rendered by Sanity's pane router\nconst PaneLinkWrapper = styled.span`\n display: block;\n min-width: 0;\n overflow: hidden;\n\n a {\n font-size: 13px;\n font-weight: 600;\n color: #4f46e5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n text-decoration: none;\n display: block;\n transition: color 0.15s;\n\n &:hover {\n color: #4338ca;\n text-decoration: underline;\n }\n }\n`\n\n// Sub-component for desk-structure split-pane navigation.\n// Uses ChildLink from usePaneRouter to open the document editor to the right\n// while keeping the SEO Health pane visible on the left.\nconst DocTitleAnchorPane: React.FC<{id: string; type: string; children: React.ReactNode}> = ({\n id,\n type,\n children,\n}) => {\n const {ChildLink} = usePaneRouter()\n return (\n <PaneLinkWrapper>\n <ChildLink childId={id} childParameters={{type}}>\n {children}\n </ChildLink>\n </PaneLinkWrapper>\n )\n}\n\n// Sub-component to safely call docBadge outside a .map expression\nconst DocBadgeRenderer: React.FC<{\n doc: DocumentWithSeoHealth & Record<string, unknown>\n docBadge: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n}> = ({doc, docBadge}) => {\n const badge = docBadge(doc)\n if (!badge) return null\n return (\n <CustomBadge $bgColor={badge.bgColor} $textColor={badge.textColor} $fontSize={badge.fontSize}>\n {badge.label}\n </CustomBadge>\n )\n}\n\nconst Spinner = styled.div`\n width: 28px;\n height: 28px;\n border: 3px solid #e5e7eb;\n border-top-color: #6366f1;\n border-radius: 50%;\n animation: ${spin} 0.7s linear infinite;\n margin: 0 auto 12px;\n`\n\nconst LoadingState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #6b7280;\n font-size: 13px;\n`\n\nconst EmptyState = styled.div`\n padding: 48px 24px;\n text-align: center;\n color: #9ca3af;\n font-size: 13px;\n`\n\nconst DeprecationBanner = styled.div`\n background: #fffbeb;\n border: 1px solid #fcd34d;\n border-radius: 8px;\n padding: 10px 14px;\n font-size: 12px;\n color: #78350f;\n margin-bottom: 16px;\n line-height: 1.6;\n`\n\nconst DeprecationBannerLink = styled.a`\n color: #92400e;\n font-weight: 600;\n text-decoration: underline;\n &:hover {\n color: #78350f;\n }\n`\n\n/**\n * Color palette for dynamic document type badges\n * Colors are randomly assigned based on type hash for visual variety\n * while maintaining consistency across sessions\n */\nconst TYPE_COLOR_PALETTE: Array<{bg: string; text: string}> = [\n {bg: '#dbeafe', text: '#0c4a6e'}, // Blue\n {bg: '#dcfce7', text: '#14532d'}, // Green\n {bg: '#fce7f3', text: '#500724'}, // Pink\n {bg: '#fed7aa', text: '#7c2d12'}, // Orange\n {bg: '#e9d5ff', text: '#581c87'}, // Purple\n {bg: '#f3e8ff', text: '#3f0f5c'}, // Deep Purple\n {bg: '#ccfbf1', text: '#134e4a'}, // Teal\n {bg: '#ddd6fe', text: '#3730a3'}, // Indigo\n {bg: '#fca5a5', text: '#7f1d1d'}, // Red\n {bg: '#a7f3d0', text: '#065f46'}, // Emerald\n {bg: '#fbbf24', text: '#78350f'}, // Amber\n {bg: '#c4b5fd', text: '#3b0764'}, // Violet\n {bg: '#f0fdf4', text: '#15803d'}, // Light Green\n {bg: '#fef2f2', text: '#991b1b'}, // Light Red\n {bg: '#f5f3ff', text: '#5b21b6'}, // Light Purple\n {bg: '#fffbeb', text: '#92400e'}, // Light Amber\n]\n\n/**\n * Get dynamic color for a document type based on type name hash\n * Same type always gets the same color, but assignment is not fixed\n */\nconst getTypeColor = (type: string): {bg: string; text: string} => {\n // Generate consistent hash from type string using simple arithmetic\n let hash = 0\n for (let i = 0; i < type.length; i += 1) {\n const char = type.charCodeAt(i)\n hash = Math.abs(hash * 31 + char)\n }\n\n // Use modulo to get index within palette range\n const colorIndex = hash % TYPE_COLOR_PALETTE.length\n return TYPE_COLOR_PALETTE[colorIndex]\n}\n\nconst getStatusCategory = (score: number): SeoHealthMetrics['status'] => {\n if (score >= 80) return 'excellent'\n if (score >= 60) return 'good'\n if (score >= 40) return 'fair'\n if (score > 0) return 'poor'\n return 'missing'\n}\n\nconst scoreMetaTitle = (title?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (title && title.length >= 50 && title.length <= 60) {\n score = 15\n } else if (title && title.length > 0) {\n score = 10\n if (title.length < 50) issues.push('Meta title too short (< 50 chars)')\n if (title.length > 60) issues.push('Meta title too long (> 60 chars)')\n } else {\n issues.push('Missing meta title')\n }\n\n return {score, issues}\n}\n\nconst scoreMetaDescription = (description?: string): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (description && description.length >= 120 && description.length <= 160) {\n score = 15\n } else if (description && description.length > 0) {\n score = 10\n if (description.length < 120) issues.push('Meta description too short (< 120 chars)')\n if (description.length > 160) issues.push('Meta description too long (> 160 chars)')\n } else {\n issues.push('Missing meta description')\n }\n\n return {score, issues}\n}\n\nconst scoreOpenGraph = (openGraph?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (openGraph) {\n if (openGraph.title) score += 6\n else issues.push('Missing OG title')\n\n if (openGraph.description) score += 6\n else issues.push('Missing OG description')\n\n if (openGraph.image) score += 6\n else issues.push('Missing OG image')\n\n if (openGraph.type) score += 7\n else issues.push('Missing OG type')\n } else {\n issues.push('Open Graph not configured')\n }\n\n return {score, issues}\n}\n\nconst scoreTwitterCard = (twitter?: Record<string, unknown>): {score: number; issues: string[]} => {\n const issues: string[] = []\n let score = 0\n\n if (twitter) {\n if (twitter.title) score += 5\n else issues.push('Missing Twitter title')\n\n if (twitter.description) score += 5\n else issues.push('Missing Twitter description')\n\n if (twitter.image) score += 5\n else issues.push('Missing Twitter image')\n } else {\n issues.push('Twitter Card not configured')\n }\n\n return {score, issues}\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst calculateHealthScore = (doc: any): SeoHealthMetrics => {\n if (!doc.seo) {\n return {score: 0, status: 'missing', issues: ['SEO fields not configured']}\n }\n\n const {title, description, keywords, robots, canonicalUrl, openGraph, twitter} = doc.seo\n let score = 0\n const issues: string[] = []\n\n const titleResult = scoreMetaTitle(title)\n score += titleResult.score\n issues.push(...titleResult.issues)\n\n const descResult = scoreMetaDescription(description)\n score += descResult.score\n issues.push(...descResult.issues)\n\n // Image\n if (doc.seo.metaImage) score += 10\n else issues.push('Missing meta image')\n\n // Keywords\n if (keywords && keywords.length > 0) score += 10\n else issues.push('No keywords defined')\n\n // Robots\n if (robots && !robots.noIndex) score += 5\n else if (!robots) score += 5\n\n // Canonical URL\n if (canonicalUrl) score += 0 // bonus, not counted in base\n\n const ogResult = scoreOpenGraph(openGraph)\n score += ogResult.score\n issues.push(...ogResult.issues)\n\n const twResult = scoreTwitterCard(twitter)\n score += twResult.score\n issues.push(...twResult.issues)\n\n // Image Completeness bonus (+5 pts when all three images are present)\n const hasMetaImage = !!doc.seo.metaImage\n const hasOgImage = !!(openGraph && openGraph.image)\n const hasTwitterImage = !!(twitter && twitter.image)\n if (hasMetaImage && hasOgImage && hasTwitterImage) {\n score += 5\n } else {\n const missingImages: string[] = []\n if (!hasMetaImage) missingImages.push('meta image')\n if (!hasOgImage) missingImages.push('OG image')\n if (!hasTwitterImage) missingImages.push('Twitter image')\n issues.push(`Missing images for full score: ${missingImages.join(', ')}`)\n }\n\n const status = getStatusCategory(score)\n return {score, status, issues}\n}\n\nconst resolveTypeLabel = (type: string, typeLabels?: Record<string, string>): string =>\n typeLabels?.[type] ?? type\n\n/**\n * Builds the GROQ projection snippet for the title field.\n * - undefined / 'title' → `title`\n * - 'name' → `\"title\": name`\n * - { post: 'title', product: 'name' } → `\"title\": select(_type == \"post\" => title, _type == \"product\" => name, title)`\n */\nconst buildTitleProjection = (titleField?: string | Record<string, string>): string => {\n if (!titleField || titleField === 'title') return 'title'\n if (typeof titleField === 'string') return `\"title\": ${titleField}`\n const cases = Object.entries(titleField)\n .map(([type, field]) => `_type == \"${type}\" => ${field}`)\n .join(', ')\n return `\"title\": select(${cases}, title)`\n}\n\nexport interface SeoHealthDashboardProps {\n icon?: string\n title?: string\n description?: string\n showTypeColumn?: boolean\n showDocumentId?: boolean\n /**\n * Limit the dashboard to specific document type names.\n * If both queryTypes and customQuery are provided, customQuery takes precedence.\n */\n queryTypes?: string[]\n /**\n * When using `queryTypes`, also filter by `seo != null`.\n * Set to `false` to include documents of those types even without an seo field.\n * Defaults to `true`.\n */\n queryRequireSeo?: boolean\n /**\n * A fully custom GROQ query used to fetch documents.\n * Must return objects with at least: _id, _type, title, seo, _updatedAt\n * Takes precedence over queryTypes.\n */\n customQuery?: string\n /**\n * The Sanity API version to use for the client (e.g. '2023-01-01').\n * Defaults to '2023-01-01'.\n */\n apiVersion?: string\n /**\n * License key for the SEO Health Dashboard.\n * Obtain a key at https://sanity-plugin-seofields.thehardik.in\n */\n licenseKey?: string\n /**\n * Map raw `_type` values to human-readable display labels used in the\n * Type column and the Type filter dropdown.\n * Replaces the deprecated `typeLabels`.\n * Any type without an entry falls back to the raw `_type` string.\n *\n * @example\n * typeDisplayLabels={{ productDrug: 'Products', singleCondition: 'Condition' }}\n */\n typeDisplayLabels?: Record<string, string>\n /**\n * Controls how the type is rendered in the Type column.\n * - `'badge'` (default) — coloured pill, consistent with score badges\n * - `'text'` — plain text, useful for dense layouts\n */\n typeColumnMode?: 'badge' | 'text'\n /**\n * The document field to use as the display title.\n *\n * - `string` — use this field for every document type (e.g. `'name'`)\n * - `Record<string, string>` — per-type mapping; unmapped types fall back to `title`\n *\n * @example\n * // Same field for all types\n * titleField: 'name'\n *\n * @example\n * // Different field per type\n * titleField: { post: 'title', product: 'name', category: 'label' }\n */\n titleField?: string | Record<string, string>\n /**\n * Callback function to render a custom badge next to the document title.\n * Replaces the deprecated `docBadge`.\n * Receives the full document and should return badge data or undefined.\n *\n * @example\n * getDocumentBadge: (doc) => {\n * if (doc.services === 'NHS')\n * return { label: 'NHS', bgColor: '#e0f2fe', textColor: '#0369a1' }\n * if (doc.services === 'Private')\n * return { label: 'Private', bgColor: '#fef3c7', textColor: '#92400e' }\n * }\n */\n getDocumentBadge?: (\n doc: DocumentWithSeoHealth & Record<string, unknown>,\n ) => {label: string; bgColor?: string; textColor?: string; fontSize?: string} | undefined\n /**\n * Custom text shown while the license key is being verified.\n * Defaults to `\"Verifying license…\"`.\n */\n loadingLicense?: React.ReactNode\n /**\n * Custom text shown while documents are being fetched.\n * Defaults to `\"Loading documents…\"`.\n */\n loadingDocuments?: React.ReactNode\n /**\n * Custom text shown when the query returns zero results.\n * Defaults to `\"No documents found\"`.\n */\n noDocuments?: React.ReactNode\n /**\n * Enable preview/demo mode to show dummy data.\n * Useful for testing, documentation, or showcasing the dashboard.\n * When enabled, displays realistic sample documents with various SEO scores.\n * Defaults to `false`.\n */\n previewMode?: boolean\n /**\n * When `true`, clicking a document title opens the document editor as a split\n * pane to the right, keeping the SEO Health pane visible on the left.\n * This uses Sanity's pane router and requires the component to be rendered\n * inside a desk-structure pane context (i.e. via `createSeoHealthPane`).\n *\n * When `false` (default), clicking navigates to the document via the standard\n * intent-link system (full navigation).\n *\n * This is set to `true` automatically by `createSeoHealthPane`.\n */\n openInPane?: boolean\n /**\n * The `name` of the Sanity structure tool that contains the monitored documents.\n * When provided, clicking a document title navigates directly to that tool's\n * intent URL (`/{basePath}/{structureTool}/intent/edit/id=…;type=…/`) instead of\n * using the generic intent resolver, which always picks the first registered tool.\n *\n * Required when you have multiple structure tools and the documents live in a\n * non-default one (e.g. `name: 'common'`).\n *\n * @example\n * structureTool: 'common'\n */\n structureTool?: string\n /**\n * @internal — populated by the plugin when deprecated config keys are detected.\n * Each entry carries the migration hint, the version it was deprecated in, and\n * the matching changelog URL so the banner can group warnings by release.\n */\n _deprecationWarnings?: DeprecationWarning[]\n}\n\n/**\n * Generate dummy data for preview mode showing various SEO health scenarios\n */\nconst generateDummyData = (): DocumentWithSeoHealth[] => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const dummyDocs: any[] = [\n {\n _id: 'preview-post-1',\n _type: 'post',\n title: 'Getting Started with SEO Best Practices',\n slug: {current: 'getting-started-seo'},\n _updatedAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Getting Started with SEO Best Practices | My Blog',\n description:\n 'Learn the fundamentals of SEO optimization to improve your website visibility and search rankings.',\n keywords: ['seo', 'best practices', 'optimization'],\n metaImage: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}},\n openGraph: {\n title: 'SEO Best Practices Guide',\n description: 'Master SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'SEO Guide'},\n type: 'article',\n },\n twitter: {\n title: 'SEO Best Practices',\n description: 'Learn SEO optimization',\n image: {_type: 'image', asset: {_ref: 'image-123', _type: 'reference'}, alt: 'Guide'},\n card: 'summary_large_image',\n },\n },\n },\n {\n _id: 'preview-post-2',\n _type: 'post',\n title: 'Advanced Analytics Strategy',\n slug: {current: 'advanced-analytics'},\n _updatedAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Advanced Analytics',\n description: 'Strategy tips',\n keywords: ['analytics', 'data'],\n openGraph: {\n title: 'Analytics Guide',\n },\n },\n },\n {\n _id: 'preview-page-1',\n _type: 'page',\n title: 'About Us',\n slug: {current: 'about'},\n _updatedAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'About',\n keywords: ['company', 'team'],\n metaImage: {_type: 'image', asset: {_ref: 'image-456', _type: 'reference'}},\n },\n },\n {\n _id: 'preview-post-3',\n _type: 'post',\n title: 'Content Marketing Trends for 2024',\n slug: {current: 'content-marketing-trends'},\n _updatedAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Content Marketing Trends 2024',\n description:\n 'Discover the latest content marketing trends and strategies to engage your audience effectively.',\n keywords: ['content marketing', 'trends', 'strategy', 'engagement'],\n metaImage: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}},\n openGraph: {\n title: 'Content Marketing Trends 2024',\n description: 'Latest trends in content marketing',\n image: {_type: 'image', asset: {_ref: 'image-789', _type: 'reference'}, alt: 'Trends'},\n type: 'article',\n },\n twitter: {\n title: 'Content Marketing Trends',\n description: 'Discover the latest trends',\n card: 'summary',\n },\n },\n },\n {\n _id: 'preview-post-4',\n _type: 'product',\n title: 'Pro Plan',\n slug: {current: 'pro-plan'},\n _updatedAt: new Date(Date.now() - 15 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Pro',\n keywords: ['pricing'],\n },\n },\n {\n _id: 'preview-page-2',\n _type: 'page',\n title: 'Contact',\n slug: {current: 'contact'},\n _updatedAt: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n openGraph: {\n title: 'Get in Touch',\n },\n },\n },\n {\n _id: 'preview-post-5',\n _type: 'post',\n title: 'Mobile Optimization Guide',\n slug: {current: 'mobile-optimization'},\n _updatedAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(),\n seo: {\n title: 'Mobile Optimization Guide: Best Practices for Responsive Design',\n description:\n 'Complete guide to mobile optimization including responsive design, performance tips, and user experience best practices for modern web development.',\n keywords: ['mobile', 'optimization', 'responsive', 'performance'],\n metaImage: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}},\n openGraph: {\n title: 'Mobile Optimization Best Practices',\n description: 'Master mobile web optimization',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n type: 'article',\n },\n twitter: {\n title: 'Mobile Optimization Tips',\n description: 'Responsive design best practices',\n image: {_type: 'image', asset: {_ref: 'image-mobile', _type: 'reference'}, alt: 'Mobile'},\n card: 'summary_large_image',\n },\n },\n },\n ]\n\n // Calculate health scores and return\n return dummyDocs.map((doc) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n}\n\nconst SeoHealthDashboard: React.FC<SeoHealthDashboardProps> = ({\n icon = '📊',\n title = 'SEO Health Dashboard',\n description = 'Monitor and optimize SEO fields across all your documents',\n showTypeColumn = true,\n showDocumentId = true,\n queryTypes,\n queryRequireSeo = true,\n customQuery,\n apiVersion = '2023-01-01',\n licenseKey,\n typeDisplayLabels,\n typeColumnMode = 'badge',\n titleField,\n getDocumentBadge,\n loadingLicense,\n loadingDocuments,\n noDocuments,\n previewMode = false,\n openInPane = false,\n structureTool,\n _deprecationWarnings,\n}) => {\n // Resolve deprecated prop pairs to their new counterparts, while allowing both to be used simultaneously for backward compatibility.\n const resolvedTypeLabels = typeDisplayLabels\n const resolvedDocBadge = getDocumentBadge\n\n // Collect all deprecation warnings to display in the UI banner\n const allDeprecationWarnings = useMemo(() => _deprecationWarnings ?? [], [_deprecationWarnings])\n\n // Group warnings by version so the banner renders one changelog link per release.\n const deprecationGroups = useMemo(() => {\n const groups = new Map<string, {version: string; changelogUrl: string; keys: string[]}>()\n for (const w of allDeprecationWarnings) {\n if (!groups.has(w.version)) {\n groups.set(w.version, {version: w.version, changelogUrl: w.changelogUrl, keys: []})\n }\n groups.get(w.version)!.keys.push(w.key)\n }\n return Array.from(groups.values())\n }, [allDeprecationWarnings])\n const client = useClient({apiVersion})\n const [licenseStatus, setLicenseStatus] = useState<'loading' | 'valid' | 'invalid'>('loading')\n const [documents, setDocuments] = useState<DocumentWithSeoHealth[]>([])\n const [loading, setLoading] = useState(true)\n const [isRefreshing, setIsRefreshing] = useState(false)\n const [searchQuery, setSearchQuery] = useState('')\n const [filterStatus, setFilterStatus] = useState<string>('all')\n const [filterType, setFilterType] = useState<string>('all')\n const [sortBy, setSortBy] = useState<'score' | 'title'>('score')\n const [activePopover, setActivePopover] = useState<{\n top: number\n left: number\n issues: string[]\n } | null>(null)\n\n const VALIDATION_ENDPOINT = 'https://sanity-plugin-seofields.thehardik.in/api/validate-license'\n const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour\n\n const validateLicense = useCallback(\n async (forceRefresh = false) => {\n // Preview mode bypasses license validation\n if (previewMode) {\n setLicenseStatus('valid')\n return\n }\n\n // No key provided\n if (!licenseKey) {\n setLicenseStatus('invalid')\n return\n }\n\n const projectId = client.config().projectId ?? ''\n const cacheKey = `seofields_license_${projectId}`\n\n if (forceRefresh) {\n try {\n sessionStorage.removeItem(cacheKey)\n } catch {\n // ignore storage errors\n }\n }\n\n // Check sessionStorage cache\n if (!forceRefresh) {\n try {\n const cached = sessionStorage.getItem(cacheKey)\n if (cached) {\n const {valid, ts} = JSON.parse(cached) as {valid: boolean; ts: number}\n if (Date.now() - ts < CACHE_TTL_MS) {\n setLicenseStatus(valid ? 'valid' : 'invalid')\n return\n }\n }\n } catch {\n // ignore storage errors\n }\n }\n\n setLicenseStatus('loading')\n\n try {\n const res = await fetch(VALIDATION_ENDPOINT, {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify({licenseKey, projectId}),\n })\n const valid = res.ok\n setLicenseStatus(valid ? 'valid' : 'invalid')\n try {\n sessionStorage.setItem(cacheKey, JSON.stringify({valid, ts: Date.now()}))\n } catch {\n // ignore storage errors\n }\n } catch {\n // Network error — fail open to avoid blocking legitimate users\n setLicenseStatus('valid')\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [licenseKey, previewMode],\n )\n\n useEffect(() => {\n validateLicense()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [licenseKey, previewMode])\n\n const handleMouseEnterIssues = (el: HTMLDivElement | null, issues: string[]) => {\n if (!el) return\n const rect = el.getBoundingClientRect()\n const popoverWidth = 280\n const viewportWidth = window.innerWidth\n\n // Align popover left edge to trigger left edge, clamp within viewport\n let left = rect.left\n if (left + popoverWidth > viewportWidth - 10) left = viewportWidth - popoverWidth - 10\n if (left < 10) left = 10\n\n setActivePopover({top: rect.top, left, issues})\n }\n\n const JSONStringifiedQueryTypes = JSON.stringify(queryTypes)\n const JSONStringifiedTitleField = JSON.stringify(titleField)\n\n const fetchDocuments = useCallback(\n async (isManualRefresh = false) => {\n try {\n if (isManualRefresh) {\n setIsRefreshing(true)\n } else {\n setLoading(true)\n }\n\n // Use dummy data in preview mode\n if (previewMode) {\n setDocuments(generateDummyData())\n return\n }\n\n let groqQuery: string\n let params: Record<string, unknown> = {}\n\n if (customQuery) {\n // Mode 3: fully custom GROQ (user-provided)\n groqQuery = customQuery\n } else if (queryTypes && queryTypes.length > 0) {\n // Mode 2: filter by specific document types (excluding drafts)\n const seoFilter = queryRequireSeo ? ' && seo != null' : ''\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[_type in $types${seoFilter} && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n params = {types: queryTypes}\n } else {\n // Mode 1: default — all documents with an seo field (excluding drafts)\n const titleProj = buildTitleProjection(titleField)\n groqQuery = `*[seo != null && !(_id in path(\"drafts.**\"))]{\n _id,\n _type,\n ${titleProj},\n slug,\n seo,\n _updatedAt\n }`\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await client.fetch(groqQuery, params, {perspective: 'published'})\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const docsWithHealth: DocumentWithSeoHealth[] = result.map((doc: any) => ({\n ...doc,\n health: calculateHealthScore(doc),\n }))\n\n setDocuments(docsWithHealth)\n } catch (error) {\n console.error('Error fetching documents:', error)\n } finally {\n setLoading(false)\n setIsRefreshing(false)\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n client,\n customQuery,\n queryRequireSeo,\n JSONStringifiedQueryTypes,\n JSONStringifiedTitleField,\n previewMode,\n ],\n )\n\n useEffect(() => {\n fetchDocuments()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n client,\n customQuery,\n queryRequireSeo,\n JSONStringifiedQueryTypes,\n JSONStringifiedTitleField,\n previewMode,\n ])\n\n const handleRefresh = useCallback(() => {\n fetchDocuments(true)\n }, [fetchDocuments])\n\n const uniqueDocumentTypes = useMemo(() => {\n const types = new Set(documents.map((doc) => doc._type))\n return Array.from(types).sort()\n }, [documents])\n\n const filteredAndSortedDocs = useMemo(() => {\n let filtered = documents\n\n if (searchQuery) {\n filtered = filtered.filter(\n (doc) =>\n doc.title?.toLowerCase().includes(searchQuery.toLowerCase()) ||\n doc._id?.toLowerCase().includes(searchQuery.toLowerCase()),\n )\n }\n\n if (filterStatus !== 'all') {\n filtered = filtered.filter((doc) => doc.health.status === filterStatus)\n }\n\n if (filterType !== 'all') {\n filtered = filtered.filter((doc) => doc._type === filterType)\n }\n\n const sorted = [...filtered].sort((a, b) => {\n if (sortBy === 'score') {\n return b.health.score - a.health.score\n }\n return (a.title || '').localeCompare(b.title || '')\n })\n\n return sorted\n }, [documents, searchQuery, filterStatus, filterType, sortBy])\n\n const stats = useMemo(() => {\n const total = documents.length\n const excellent = documents.filter((d) => d.health.score >= 80).length\n const good = documents.filter((d) => d.health.score >= 60 && d.health.score < 80).length\n const fair = documents.filter((d) => d.health.score >= 40 && d.health.score < 60).length\n const poor = documents.filter((d) => d.health.score > 0 && d.health.score < 40).length\n const missing = documents.filter((d) => d.health.score === 0).length\n\n const avgScore =\n total > 0 ? Math.round(documents.reduce((sum, d) => sum + d.health.score, 0) / total) : 0\n\n return {total, excellent, good, fair, poor, missing, avgScore}\n }, [documents])\n\n const handleMouseLeave = useCallback(() => {\n setActivePopover(null)\n }, [])\n\n return (\n <DashboardContainer>\n {licenseStatus === 'loading' && (\n <LoadingState style={{padding: '80px 24px'}}>\n <Spinner />\n {loadingLicense ?? 'Verifying license…'}\n </LoadingState>\n )}\n {licenseStatus === 'invalid' && (\n <UpgradeContainer>\n <UpgradeBox>\n {licenseKey ? (\n <>\n <UpgradeLock>❌</UpgradeLock>\n <UpgradeTitle>Invalid License Key</UpgradeTitle>\n <UpgradeText>\n The license key you provided is invalid or has been revoked. Please check your key\n and update it in the plugin config.\n </UpgradeText>\n <UpgradeCode>{`seofields({\n healthDashboard: {\n licenseKey: 'YOUR_LICENSE_KEY', // ← replace with a valid key\n },\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a New License Key →\n </UpgradeButton>\n <br />\n {/* eslint-disable-next-line react/jsx-no-bind */}\n <ReloadButton onClick={() => validateLicense(true)}>\n Click here If You Just Updated Your Key\n </ReloadButton>\n </>\n ) : (\n <>\n <UpgradeLock>🔒</UpgradeLock>\n <UpgradeTitle>SEO Health Dashboard</UpgradeTitle>\n <UpgradeText>\n This feature requires a license key. Add your key to the plugin config to unlock\n the full dashboard.\n </UpgradeText>\n <UpgradeCode>{`// sanity.config.ts\nimport { seofields } from 'sanity-plugin-seofields'\n\nexport default defineConfig({\n plugins: [\n seofields({\n healthDashboard: {\n licenseKey: 'SEOF-XXXX-XXXX-XXXX',\n },\n }),\n ],\n})`}</UpgradeCode>\n <UpgradeButton\n href=\"https://sanity-plugin-seofields.thehardik.in\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Get a License Key →\n </UpgradeButton>\n </>\n )}\n </UpgradeBox>\n </UpgradeContainer>\n )}\n {licenseStatus === 'valid' && (\n <>\n {/* Header */}\n <PageHeader>\n <div>\n <PageTitle>\n <span>\n {icon} {title}\n </span>\n {previewMode && <PreviewBadge>Preview Mode</PreviewBadge>}\n </PageTitle>\n <PageSubtitle>{description}</PageSubtitle>\n </div>\n <DashboardRefreshButton\n onClick={handleRefresh}\n disabled={loading || isRefreshing}\n $spinning={isRefreshing}\n title=\"Refresh documents\"\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <polyline points=\"23 4 23 10 17 10\" />\n <polyline points=\"1 20 1 14 7 14\" />\n <path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\" />\n </svg>\n Refresh\n </DashboardRefreshButton>\n </PageHeader>\n {/* Deprecation warning banner */}\n {deprecationGroups.length > 0 && (\n <DeprecationBanner>\n <strong>⚠️ Deprecated config keys detected:</strong>{' '}\n {deprecationGroups.map((group, gi) => (\n <span key={group.version}>\n {group.keys.map((w, i) => (\n <span key={w}>\n <code style={{background: '#fef9c3', padding: '1px 4px', borderRadius: 3}}>\n {w.split('→')[0].trim()}\n </code>\n {' → '}\n <code style={{background: '#dcfce7', padding: '1px 4px', borderRadius: 3}}>\n {w.split('→')[1].trim()}\n </code>\n {i < group.keys.length - 1 ? ' · ' : ''}\n </span>\n ))}{' '}\n (\n <DeprecationBannerLink\n href={group.changelogUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {group.version} changelog\n </DeprecationBannerLink>\n ){gi < deprecationGroups.length - 1 ? ' · ' : ''}\n </span>\n ))}{' '}\n — Please update your config.\n </DeprecationBanner>\n )}\n {/* Stats Grid */}\n {!loading && (\n <StatsGrid>\n <StatCard>\n <StatLabel>Total Docs</StatLabel>\n <StatValue>{stats.total}</StatValue>\n </StatCard>\n <StatCard>\n <StatLabel>Avg Score</StatLabel>\n <StatValue>{stats.avgScore}%</StatValue>\n </StatCard>\n <StatCard $accent=\"#10b981\">\n <StatLabel>Excellent (80+)</StatLabel>\n <StatValue>{stats.excellent}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f59e0b\">\n <StatLabel>Good (60–79)</StatLabel>\n <StatValue>{stats.good}</StatValue>\n </StatCard>\n <StatCard $accent=\"#f97316\">\n <StatLabel>Fair (40–59)</StatLabel>\n <StatValue>{stats.fair}</StatValue>\n </StatCard>\n <StatCard $accent=\"#ef4444\">\n <StatLabel>Poor / Missing</StatLabel>\n <StatValue>{stats.poor + stats.missing}</StatValue>\n </StatCard>\n </StatsGrid>\n )}\n {/* Controls */}\n <ControlsBar>\n <SearchWrapper>\n <SearchIconSvg>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </SearchIconSvg>\n <SearchInput\n placeholder=\"Search documents...\"\n value={searchQuery}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSearchQuery(e.currentTarget.value)}\n />\n </SearchWrapper>\n <StyledSelect\n value={filterStatus}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterStatus(e.currentTarget.value)}\n >\n <option value=\"all\">All Status</option>\n <option value=\"excellent\">Excellent</option>\n <option value=\"good\">Good</option>\n <option value=\"fair\">Fair</option>\n <option value=\"poor\">Poor</option>\n <option value=\"missing\">Missing</option>\n </StyledSelect>\n {uniqueDocumentTypes.length > 1 && (\n <StyledSelect\n value={filterType}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setFilterType(e.currentTarget.value)}\n >\n <option value=\"all\">All Types</option>\n {uniqueDocumentTypes.map((type) => (\n <option key={type} value={type}>\n {resolveTypeLabel(type, resolvedTypeLabels)}\n </option>\n ))}\n </StyledSelect>\n )}\n <StyledSelect\n value={sortBy}\n // eslint-disable-next-line react/jsx-no-bind\n onChange={(e) => setSortBy(e.currentTarget.value as 'score' | 'title')}\n >\n <option value=\"score\">Sort by Score</option>\n <option value=\"title\">Sort by Title</option>\n </StyledSelect>\n </ControlsBar>\n {/* Documents Table */}\n <TableCard>\n {loading && (\n <LoadingState>\n <Spinner />\n {loadingDocuments ?? 'Loading documents…'}\n </LoadingState>\n )}\n {!loading &&\n (filteredAndSortedDocs.length === 0 ? (\n <EmptyState>{noDocuments ?? 'No documents found'}</EmptyState>\n ) : (\n <>\n <TableHeader>\n <ColTitle>Title</ColTitle>\n {showTypeColumn && <ColType>Type</ColType>}\n <ColScore>Score</ColScore>\n <ColIssues>Top Issues</ColIssues>\n </TableHeader>\n {filteredAndSortedDocs.map((doc) => {\n return (\n <TableRow key={doc._id}>\n <ColTitle>\n <TitleWrapper>\n <TitleCell>\n {doc.title !== null && typeof doc.title !== 'string' ? (\n <NonStringTitleWarning title=\"title is not a string — use pt::text(title) in your query.groq projection to convert Portable Text to a plain string\">\n ⚠ title is not a string — use pt::text(title) in query.groq\n </NonStringTitleWarning>\n ) : (\n <>\n {openInPane ? (\n <DocTitleAnchorPane id={doc._id} type={doc._type}>\n {typeof doc.title === 'string'\n ? doc.title || 'Untitled'\n : 'Untitled'}\n </DocTitleAnchorPane>\n ) : (\n <DocTitleAnchor\n id={doc._id}\n type={doc._type}\n structureTool={structureTool}\n >\n {typeof doc.title === 'string'\n ? doc.title || 'Untitled'\n : 'Untitled'}\n </DocTitleAnchor>\n )}\n </>\n )}\n {showDocumentId && <DocId>{doc._id}</DocId>}\n {resolvedDocBadge && (\n <DocBadgeRenderer\n doc={doc as DocumentWithSeoHealth & Record<string, unknown>}\n docBadge={resolvedDocBadge}\n />\n )}\n </TitleCell>\n </TitleWrapper>\n </ColTitle>\n {showTypeColumn && (\n <ColType>\n {typeColumnMode === 'text' ? (\n <TypeText>{resolveTypeLabel(doc._type, resolvedTypeLabels)}</TypeText>\n ) : (\n (() => {\n const typeColor = getTypeColor(doc._type)\n return (\n <TypeBadge $bgColor={typeColor.bg} $textColor={typeColor.text}>\n {resolveTypeLabel(doc._type, resolvedTypeLabels)}\n </TypeBadge>\n )\n })()\n )}\n </ColType>\n )}\n <ColScore>\n <ScoreBadge $score={doc.health.score}>{doc.health.score}%</ScoreBadge>\n </ColScore>\n <ColIssues>\n {doc.health.issues.slice(0, 2).map((issue) => (\n <IssueTag key={`issue-${doc._id}-${issue}`}>• {issue}</IssueTag>\n ))}\n {doc.health.issues.length > 2 && (\n <MoreIssuesWrapper\n // eslint-disable-next-line react/jsx-no-bind\n onMouseEnter={function (e) {\n handleMouseEnterIssues(\n e.currentTarget as HTMLDivElement,\n doc.health.issues.slice(2),\n )\n }}\n onMouseLeave={handleMouseLeave}\n >\n <MoreIssues>+{doc.health.issues.length - 2} more issues</MoreIssues>\n </MoreIssuesWrapper>\n )}\n </ColIssues>\n </TableRow>\n )\n })}\n </>\n ))}\n </TableCard>\n {/* Single shared popover rendered outside the table */}\n {activePopover && (\n <IssuesPopover\n style={{\n top: activePopover.top,\n left: activePopover.left,\n transform: 'translateY(calc(-100% - 10px))',\n }}\n >\n {activePopover.issues.map((issue) => (\n <PopoverIssueItem key={issue}>⚠️ {issue}</PopoverIssueItem>\n ))}\n </IssuesPopover>\n )}{' '}\n </>\n )}{' '}\n </DashboardContainer>\n )\n}\n\nexport default SeoHealthDashboard\n"]}
package/dist/cli.js ADDED
@@ -0,0 +1,67 @@
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(`
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.
7
+ Options:
8
+ 1. Create a seofields.cli.ts file with defineSeoCli({ projectId: "..." })
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(`
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'
19
+
20
+ export default defineSeoCli({
21
+ projectId: '${e}',
22
+ dataset: '${t}',
23
+ token: process.env.SANITY_TOKEN,
24
+
25
+ // Document types that have SEO fields \u2014 used by \`report\` and \`export\`
26
+ // types: ['post', 'page'],
27
+ })
28
+ `,Je=(e,t)=>`import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'
29
+
30
+ export default defineSeoCli({
31
+ projectId: '${e}',
32
+ dataset: '${t}',
33
+ token: process.env.SANITY_TOKEN,
34
+
35
+ // Document types that have SEO fields \u2014 used by \`report\` and \`export\`
36
+ // types: ['post', 'page'],
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)]{
41
+ _id,
42
+ _type,
43
+ _updatedAt,
44
+ title,
45
+ slug,
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(`
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
+ ${s}${e.slice(r)}`:`${s}
51
+
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.
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)]{
58
+ _id,
59
+ _type,
60
+ _updatedAt,
61
+ title,
62
+ slug,
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.0",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();
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ require('./chunk-S367Y35J.cjs');
4
+
5
+ // src/define-cli.ts
6
+ function defineSeoCli(config) {
7
+ return config;
8
+ }
9
+
10
+ exports.defineSeoCli = defineSeoCli;
11
+ //# sourceMappingURL=define-cli.cjs.map
12
+ //# sourceMappingURL=define-cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/define-cli.ts"],"names":[],"mappings":";;;;;AAyCO,SAAS,aAAa,MAAA,EAAgD;AAC3E,EAAA,OAAO,MAAA;AACT","file":"define-cli.cjs","sourcesContent":["/**\n * Configuration helper for `seofields` CLI.\n *\n * Create a `seofields.cli.ts` (or `.js`) file in your project root and\n * use `defineSeoCli()` to configure the CLI without passing flags every time.\n *\n * @example\n * ```ts\n * // seofields.cli.ts\n * import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'\n *\n * export default defineSeoCli({\n * projectId: 'my-project-id',\n * dataset: 'production',\n * token: process.env.SANITY_TOKEN,\n * types: ['post', 'page', 'article'],\n * })\n * ```\n */\n\nexport interface SeoFieldsCliConfig {\n /** Sanity project ID */\n projectId?: string\n /** Sanity dataset name (default: \"production\") */\n dataset?: string\n /** Sanity API token (read access at minimum) */\n token?: string\n /** Default document types for `report` and `export` commands */\n types?: string[]\n /**\n * Show connection info (project ID, dataset, token source) at the end of\n * `report` and `export` output. Useful for debugging which credentials\n * are being used. Defaults to `false`.\n */\n showConnectionInfo?: boolean\n}\n\n/**\n * Define CLI configuration for sanity-plugin-seofields commands.\n * Acts as an identity function — provides type safety for the config object.\n */\nexport function defineSeoCli(config: SeoFieldsCliConfig): SeoFieldsCliConfig {\n return config\n}\n"]}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Configuration helper for `seofields` CLI.
3
+ *
4
+ * Create a `seofields.cli.ts` (or `.js`) file in your project root and
5
+ * use `defineSeoCli()` to configure the CLI without passing flags every time.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // seofields.cli.ts
10
+ * import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'
11
+ *
12
+ * export default defineSeoCli({
13
+ * projectId: 'my-project-id',
14
+ * dataset: 'production',
15
+ * token: process.env.SANITY_TOKEN,
16
+ * types: ['post', 'page', 'article'],
17
+ * })
18
+ * ```
19
+ */
20
+ interface SeoFieldsCliConfig {
21
+ /** Sanity project ID */
22
+ projectId?: string;
23
+ /** Sanity dataset name (default: "production") */
24
+ dataset?: string;
25
+ /** Sanity API token (read access at minimum) */
26
+ token?: string;
27
+ /** Default document types for `report` and `export` commands */
28
+ types?: string[];
29
+ /**
30
+ * Show connection info (project ID, dataset, token source) at the end of
31
+ * `report` and `export` output. Useful for debugging which credentials
32
+ * are being used. Defaults to `false`.
33
+ */
34
+ showConnectionInfo?: boolean;
35
+ }
36
+ /**
37
+ * Define CLI configuration for sanity-plugin-seofields commands.
38
+ * Acts as an identity function — provides type safety for the config object.
39
+ */
40
+ declare function defineSeoCli(config: SeoFieldsCliConfig): SeoFieldsCliConfig;
41
+
42
+ export { type SeoFieldsCliConfig, defineSeoCli };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Configuration helper for `seofields` CLI.
3
+ *
4
+ * Create a `seofields.cli.ts` (or `.js`) file in your project root and
5
+ * use `defineSeoCli()` to configure the CLI without passing flags every time.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // seofields.cli.ts
10
+ * import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'
11
+ *
12
+ * export default defineSeoCli({
13
+ * projectId: 'my-project-id',
14
+ * dataset: 'production',
15
+ * token: process.env.SANITY_TOKEN,
16
+ * types: ['post', 'page', 'article'],
17
+ * })
18
+ * ```
19
+ */
20
+ interface SeoFieldsCliConfig {
21
+ /** Sanity project ID */
22
+ projectId?: string;
23
+ /** Sanity dataset name (default: "production") */
24
+ dataset?: string;
25
+ /** Sanity API token (read access at minimum) */
26
+ token?: string;
27
+ /** Default document types for `report` and `export` commands */
28
+ types?: string[];
29
+ /**
30
+ * Show connection info (project ID, dataset, token source) at the end of
31
+ * `report` and `export` output. Useful for debugging which credentials
32
+ * are being used. Defaults to `false`.
33
+ */
34
+ showConnectionInfo?: boolean;
35
+ }
36
+ /**
37
+ * Define CLI configuration for sanity-plugin-seofields commands.
38
+ * Acts as an identity function — provides type safety for the config object.
39
+ */
40
+ declare function defineSeoCli(config: SeoFieldsCliConfig): SeoFieldsCliConfig;
41
+
42
+ export { type SeoFieldsCliConfig, defineSeoCli };
@@ -0,0 +1,10 @@
1
+ import './chunk-2NMEKWO5.js';
2
+
3
+ // src/define-cli.ts
4
+ function defineSeoCli(config) {
5
+ return config;
6
+ }
7
+
8
+ export { defineSeoCli };
9
+ //# sourceMappingURL=define-cli.js.map
10
+ //# sourceMappingURL=define-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/define-cli.ts"],"names":[],"mappings":";;;AAyCO,SAAS,aAAa,MAAA,EAAgD;AAC3E,EAAA,OAAO,MAAA;AACT","file":"define-cli.js","sourcesContent":["/**\n * Configuration helper for `seofields` CLI.\n *\n * Create a `seofields.cli.ts` (or `.js`) file in your project root and\n * use `defineSeoCli()` to configure the CLI without passing flags every time.\n *\n * @example\n * ```ts\n * // seofields.cli.ts\n * import { defineSeoCli } from 'sanity-plugin-seofields/define-cli'\n *\n * export default defineSeoCli({\n * projectId: 'my-project-id',\n * dataset: 'production',\n * token: process.env.SANITY_TOKEN,\n * types: ['post', 'page', 'article'],\n * })\n * ```\n */\n\nexport interface SeoFieldsCliConfig {\n /** Sanity project ID */\n projectId?: string\n /** Sanity dataset name (default: \"production\") */\n dataset?: string\n /** Sanity API token (read access at minimum) */\n token?: string\n /** Default document types for `report` and `export` commands */\n types?: string[]\n /**\n * Show connection info (project ID, dataset, token source) at the end of\n * `report` and `export` output. Useful for debugging which credentials\n * are being used. Defaults to `false`.\n */\n showConnectionInfo?: boolean\n}\n\n/**\n * Define CLI configuration for sanity-plugin-seofields commands.\n * Acts as an identity function — provides type safety for the config object.\n */\nexport function defineSeoCli(config: SeoFieldsCliConfig): SeoFieldsCliConfig {\n return config\n}\n"]}