sanity-plugin-seofields 1.8.0 → 1.10.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.
- package/README.md +508 -26
- package/dist/SeoHealthTool-2COI27KI.cjs +8 -0
- package/dist/SeoHealthTool-2COI27KI.cjs.map +1 -0
- package/dist/SeoHealthTool-CWI3KB2V.js +8 -0
- package/dist/SeoHealthTool-CWI3KB2V.js.map +1 -0
- package/dist/{SeoPreview-3EXR6FD4.cjs → SeoPreview-LMZAWWOE.cjs} +35 -38
- package/dist/SeoPreview-LMZAWWOE.cjs.map +1 -0
- package/dist/{SeoPreview-4PPAF4NO.js → SeoPreview-UNQBKTQO.js} +14 -11
- package/dist/SeoPreview-UNQBKTQO.js.map +1 -0
- package/dist/{chunk-B5IVI5LP.cjs → chunk-5XTQRILL.cjs} +286 -236
- package/dist/chunk-5XTQRILL.cjs.map +1 -0
- package/dist/{chunk-254YHUN3.cjs → chunk-7N4MLTMR.js} +8 -6
- package/dist/chunk-7N4MLTMR.js.map +1 -0
- package/dist/{chunk-DDAAVRWG.js → chunk-A57XNQC7.cjs} +9 -4
- package/dist/chunk-A57XNQC7.cjs.map +1 -0
- package/dist/chunk-BWLJDK5J.js +624 -0
- package/dist/chunk-BWLJDK5J.js.map +1 -0
- package/dist/chunk-CRCXC45D.js +56 -0
- package/dist/chunk-CRCXC45D.js.map +1 -0
- package/dist/chunk-EUG4MNRC.cjs +713 -0
- package/dist/chunk-EUG4MNRC.cjs.map +1 -0
- package/dist/{chunk-ZBHLMQTS.cjs → chunk-HHO2AKAP.js} +44 -17
- package/dist/chunk-HHO2AKAP.js.map +1 -0
- package/dist/chunk-NLEB47UV.js +713 -0
- package/dist/chunk-NLEB47UV.js.map +1 -0
- package/dist/chunk-OULUDJPI.cjs +254 -0
- package/dist/chunk-OULUDJPI.cjs.map +1 -0
- package/dist/chunk-R2U7JF7U.cjs +624 -0
- package/dist/chunk-R2U7JF7U.cjs.map +1 -0
- package/dist/chunk-XD4HKLEA.js +254 -0
- package/dist/chunk-XD4HKLEA.js.map +1 -0
- package/dist/chunk-XYAZJ3WX.cjs +56 -0
- package/dist/chunk-XYAZJ3WX.cjs.map +1 -0
- package/dist/{chunk-VR44E62I.js → chunk-XZKQWV2H.js} +204 -33
- package/dist/chunk-XZKQWV2H.js.map +1 -0
- package/dist/{chunk-HDZZQCH7.js → chunk-Y46ACXM4.cjs} +45 -5
- package/dist/chunk-Y46ACXM4.cjs.map +1 -0
- package/dist/cli.js +27 -27
- package/dist/{component-DEXwtemT.d.ts → component-CjT1hvxh.d.ts} +2 -2
- package/dist/{component-BzI-LHPw.d.cts → component-WYh0z8as.d.cts} +2 -2
- package/dist/define-cli.cjs +2 -4
- package/dist/define-cli.cjs.map +1 -1
- package/dist/define-cli.js +4 -4
- package/dist/define-cli.js.map +1 -1
- package/dist/head.cjs +22 -0
- package/dist/head.cjs.map +1 -0
- package/dist/head.d.cts +314 -0
- package/dist/head.d.ts +314 -0
- package/dist/head.js +22 -0
- package/dist/head.js.map +1 -0
- package/dist/hreflang-_VbSuWYD.d.cts +29 -0
- package/dist/hreflang-_VbSuWYD.d.ts +29 -0
- package/dist/index.cjs +1072 -368
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -374
- package/dist/index.d.ts +7 -374
- package/dist/index.js +1015 -288
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +212 -455
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +9 -206
- package/dist/next.d.ts +9 -206
- package/dist/next.js +189 -111
- package/dist/next.js.map +1 -1
- package/dist/plugin-HFuWZsJu.d.cts +516 -0
- package/dist/plugin-oQUCim56.d.ts +516 -0
- package/dist/schema/next.cjs +173 -327
- package/dist/schema/next.cjs.map +1 -1
- package/dist/schema/next.d.cts +4 -4
- package/dist/schema/next.d.ts +4 -4
- package/dist/schema/next.js +172 -8
- package/dist/schema/next.js.map +1 -1
- package/dist/schema.cjs +376 -517
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +5 -5
- package/dist/schema.d.ts +5 -5
- package/dist/schema.js +216 -11
- package/dist/schema.js.map +1 -1
- package/dist/server.cjs +149 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +100 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.js +149 -0
- package/dist/server.js.map +1 -0
- package/dist/{types-CW8qFdAn.d.ts → types-BAdN1RMu.d.ts} +2 -2
- package/dist/{types-B_vjMPtM.d.cts → types-C5i3KMgs.d.cts} +2 -2
- package/dist/{types-BXSCbl6p.d.cts → types-DP-DiW6f.d.cts} +2 -2
- package/dist/{types-C19cQx5D.d.ts → types-DRLUGLtX.d.ts} +2 -2
- package/dist/{types-yVmQfby9.d.cts → types-DxlPXihz.d.cts} +1 -1
- package/dist/{types-yVmQfby9.d.ts → types-DxlPXihz.d.ts} +1 -1
- package/package.json +25 -4
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js +0 -4
- package/dist/SeoHealthDashboard-AEKVVMUR-7NWV3C3Y.js.map +0 -1
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs +0 -10
- package/dist/SeoHealthDashboard-AEKVVMUR-XWKJUH24.cjs.map +0 -1
- package/dist/SeoHealthTool-2KKQJLJL.cjs +0 -11
- package/dist/SeoHealthTool-2KKQJLJL.cjs.map +0 -1
- package/dist/SeoHealthTool-3CUKGADZ.js +0 -5
- package/dist/SeoHealthTool-3CUKGADZ.js.map +0 -1
- package/dist/SeoPreview-3EXR6FD4.cjs.map +0 -1
- package/dist/SeoPreview-4PPAF4NO.js.map +0 -1
- package/dist/chunk-254YHUN3.cjs.map +0 -1
- package/dist/chunk-27XSYENH.js +0 -2215
- package/dist/chunk-27XSYENH.js.map +0 -1
- package/dist/chunk-B5IVI5LP.cjs.map +0 -1
- package/dist/chunk-BNXMFD3T.cjs +0 -431
- package/dist/chunk-BNXMFD3T.cjs.map +0 -1
- package/dist/chunk-DDAAVRWG.js.map +0 -1
- package/dist/chunk-HDZZQCH7.js.map +0 -1
- package/dist/chunk-P6IOWIO2.cjs +0 -480
- package/dist/chunk-P6IOWIO2.cjs.map +0 -1
- package/dist/chunk-UOCZFYYP.js +0 -407
- package/dist/chunk-UOCZFYYP.js.map +0 -1
- package/dist/chunk-VR44E62I.js.map +0 -1
- package/dist/chunk-WKXHX3GO.js +0 -424
- package/dist/chunk-WKXHX3GO.js.map +0 -1
- package/dist/chunk-XZDLJ2N6.cjs +0 -2224
- package/dist/chunk-XZDLJ2N6.cjs.map +0 -1
- package/dist/chunk-ZBHLMQTS.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/hardik/GITHUB/sanity-plugin-seofields/npm/dist/head.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACF,gaAAC","file":"/Users/hardik/GITHUB/sanity-plugin-seofields/npm/dist/head.cjs"}
|
package/dist/head.d.cts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { a as SanityImage, b as SanityImageWithAlt } from './types-DxlPXihz.cjs';
|
|
2
|
+
export { B as BuildHreflangsOptions, H as HreflangLinkEntry, a as HreflangTranslation, b as buildHreflangs } from './hreflang-_VbSuWYD.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Headless CMS integration helpers for sanity-plugin-seofields
|
|
6
|
+
*
|
|
7
|
+
* Provides framework-agnostic SEO metadata utilities for use with:
|
|
8
|
+
* - Next.js App Router → buildSeoMeta() inside generateMetadata()
|
|
9
|
+
* - Next.js Pages Router → <SeoMetaTags> inside Next.js <Head>
|
|
10
|
+
* - Astro / Nuxt / Vue / SvelteKit / Remix → buildSeoHead() into native head APIs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Structured metadata returned by buildSeoMeta(). Compatible with Next.js Metadata (App Router). */
|
|
14
|
+
interface SeoMetadata {
|
|
15
|
+
title?: string | null;
|
|
16
|
+
description?: string | null;
|
|
17
|
+
keywords?: string[];
|
|
18
|
+
robots?: {
|
|
19
|
+
index?: boolean;
|
|
20
|
+
follow?: boolean;
|
|
21
|
+
notranslate?: boolean;
|
|
22
|
+
noimageindex?: boolean;
|
|
23
|
+
googleBot?: {
|
|
24
|
+
index?: boolean;
|
|
25
|
+
follow?: boolean;
|
|
26
|
+
notranslate?: boolean;
|
|
27
|
+
noimageindex?: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
openGraph?: {
|
|
31
|
+
type?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
title?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
siteName?: string;
|
|
36
|
+
images?: Array<{
|
|
37
|
+
url: string;
|
|
38
|
+
width?: number;
|
|
39
|
+
height?: number;
|
|
40
|
+
alt?: string;
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
twitter?: {
|
|
44
|
+
card?: string;
|
|
45
|
+
site?: string;
|
|
46
|
+
creator?: string;
|
|
47
|
+
title?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
images?: string[];
|
|
50
|
+
};
|
|
51
|
+
alternates?: {
|
|
52
|
+
canonical?: string;
|
|
53
|
+
languages?: Record<string, string>;
|
|
54
|
+
};
|
|
55
|
+
/** Any custom meta attributes from seo.metaAttributes */
|
|
56
|
+
other?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
/** Plain `<meta>` tag data returned by buildSeoHead(). */
|
|
59
|
+
type SeoHeadMetaTag = {
|
|
60
|
+
name: string;
|
|
61
|
+
content: string;
|
|
62
|
+
} | {
|
|
63
|
+
property: string;
|
|
64
|
+
content: string;
|
|
65
|
+
};
|
|
66
|
+
/** Plain `<link>` tag data returned by buildSeoHead(). */
|
|
67
|
+
interface SeoHeadLinkTag {
|
|
68
|
+
rel: string;
|
|
69
|
+
href: string;
|
|
70
|
+
hreflang?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Framework-neutral head data returned by buildSeoHead().
|
|
74
|
+
*
|
|
75
|
+
* Use this in Astro, Nuxt, Vue, SvelteKit, Remix, or any frontend where you
|
|
76
|
+
* need plain values instead of React elements or Next.js Metadata.
|
|
77
|
+
*/
|
|
78
|
+
interface SeoHead {
|
|
79
|
+
title?: string | null;
|
|
80
|
+
meta: SeoHeadMetaTag[];
|
|
81
|
+
link: SeoHeadLinkTag[];
|
|
82
|
+
}
|
|
83
|
+
/** Default values used when SEO fields are missing. */
|
|
84
|
+
interface SeoMetaDefaults {
|
|
85
|
+
title?: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
siteName?: string;
|
|
88
|
+
twitterSite?: string;
|
|
89
|
+
twitterCreator?: string;
|
|
90
|
+
/** Fallback image URL when no OG / Twitter image is set. */
|
|
91
|
+
ogImage?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Permissive image shape accepted by buildSeoMeta — compatible with both the
|
|
95
|
+
* plugin's SanityImage and Sanity's code-generated image type (where `asset`
|
|
96
|
+
* and `alt` are optional).
|
|
97
|
+
*/
|
|
98
|
+
interface SeoImageInput {
|
|
99
|
+
_type?: string;
|
|
100
|
+
asset?: {
|
|
101
|
+
_ref: string;
|
|
102
|
+
_type: string;
|
|
103
|
+
_weak?: boolean;
|
|
104
|
+
[key: string]: unknown;
|
|
105
|
+
};
|
|
106
|
+
hotspot?: unknown;
|
|
107
|
+
crop?: unknown;
|
|
108
|
+
alt?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Input-compatible variant of SeoFields. Structurally matches Sanity's
|
|
112
|
+
* code-generated types (where `asset`, `alt`, `key`, and `type` are all
|
|
113
|
+
* optional), so you can pass `data.seo` from a sanityFetch result directly
|
|
114
|
+
* without any `as any` or manual casting.
|
|
115
|
+
*/
|
|
116
|
+
interface SeoFieldsInput {
|
|
117
|
+
_type?: string;
|
|
118
|
+
robots?: {
|
|
119
|
+
noIndex?: boolean | null;
|
|
120
|
+
noFollow?: boolean | null;
|
|
121
|
+
noTranslate?: boolean | null;
|
|
122
|
+
noImageIndex?: boolean | null;
|
|
123
|
+
} | null;
|
|
124
|
+
title?: string | null;
|
|
125
|
+
description?: string | null;
|
|
126
|
+
metaImage?: SeoImageInput | null;
|
|
127
|
+
metaAttributes?: Array<{
|
|
128
|
+
_key?: string;
|
|
129
|
+
key?: string;
|
|
130
|
+
value?: string;
|
|
131
|
+
type?: string;
|
|
132
|
+
}> | null;
|
|
133
|
+
keywords?: string[] | null;
|
|
134
|
+
canonicalUrl?: string | null;
|
|
135
|
+
hreflangs?: Array<{
|
|
136
|
+
locale?: string | null;
|
|
137
|
+
url?: string | null;
|
|
138
|
+
}> | null;
|
|
139
|
+
openGraph?: {
|
|
140
|
+
_type?: string;
|
|
141
|
+
url?: string | null;
|
|
142
|
+
title?: string | null;
|
|
143
|
+
description?: string | null;
|
|
144
|
+
siteName?: string | null;
|
|
145
|
+
type?: string | null;
|
|
146
|
+
imageType?: string | null;
|
|
147
|
+
image?: SeoImageInput | null;
|
|
148
|
+
imageUrl?: string | null;
|
|
149
|
+
} | null;
|
|
150
|
+
twitter?: {
|
|
151
|
+
_type?: string;
|
|
152
|
+
card?: string | null;
|
|
153
|
+
site?: string | null;
|
|
154
|
+
creator?: string | null;
|
|
155
|
+
title?: string | null;
|
|
156
|
+
description?: string | null;
|
|
157
|
+
imageType?: string | null;
|
|
158
|
+
image?: SeoImageInput | null;
|
|
159
|
+
imageUrl?: string | null;
|
|
160
|
+
} | null;
|
|
161
|
+
}
|
|
162
|
+
/** Options accepted by buildSeoMeta(). */
|
|
163
|
+
interface BuildSeoMetaOptions {
|
|
164
|
+
/**
|
|
165
|
+
* The raw SEO object from Sanity (_type excluded or included — both work).
|
|
166
|
+
* Pass `null` or `undefined` to fall back entirely to `defaults`.
|
|
167
|
+
*
|
|
168
|
+
* Accepts both the strict plugin `SeoFields` type and Sanity's code-generated
|
|
169
|
+
* type (which has all nested fields optional) without any `as any` cast.
|
|
170
|
+
*/
|
|
171
|
+
seo?: SeoFieldsInput | null;
|
|
172
|
+
/**
|
|
173
|
+
* The base URL of your site, e.g. "https://example.com".
|
|
174
|
+
* Used for canonical URL and OpenGraph URL construction.
|
|
175
|
+
*/
|
|
176
|
+
baseUrl?: string;
|
|
177
|
+
/**
|
|
178
|
+
* The path for the current page, e.g. "/about".
|
|
179
|
+
* Combined with baseUrl to produce the canonical + OG url.
|
|
180
|
+
* Defaults to "".
|
|
181
|
+
*/
|
|
182
|
+
path?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Default values used when the Sanity SEO fields are empty / missing.
|
|
185
|
+
*/
|
|
186
|
+
defaults?: SeoMetaDefaults;
|
|
187
|
+
/**
|
|
188
|
+
* Resolve a Sanity image asset to a plain URL string.
|
|
189
|
+
*
|
|
190
|
+
* @example (using @sanity/image-url)
|
|
191
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).url()
|
|
192
|
+
*/
|
|
193
|
+
imageUrlResolver?: (image: SanityImage | SanityImageWithAlt) => string | null | undefined;
|
|
194
|
+
/**
|
|
195
|
+
* Override the hreflang alternates. When provided, this supersedes `seo.hreflangs` — pair it with
|
|
196
|
+
* `buildHreflangs()` to derive alternates from `@sanity/document-internationalization` translations.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* hreflangs: buildHreflangs(data._translations, { baseUrl })
|
|
200
|
+
*/
|
|
201
|
+
hreflangs?: Array<{
|
|
202
|
+
locale?: string | null;
|
|
203
|
+
url?: string | null;
|
|
204
|
+
}> | null;
|
|
205
|
+
}
|
|
206
|
+
declare const VALID_OG_TYPES: readonly ["website", "article", "profile", "book", "music", "video", "product"];
|
|
207
|
+
type OGType = (typeof VALID_OG_TYPES)[number];
|
|
208
|
+
/**
|
|
209
|
+
* Coerce an arbitrary string to a valid OpenGraph type.
|
|
210
|
+
* Falls back to "website" when the value is invalid.
|
|
211
|
+
*/
|
|
212
|
+
declare function sanitizeOGType(value?: string): OGType;
|
|
213
|
+
declare const VALID_TWITTER_CARDS: readonly ["summary", "summary_large_image", "app", "player"];
|
|
214
|
+
type TwitterCard = (typeof VALID_TWITTER_CARDS)[number];
|
|
215
|
+
/**
|
|
216
|
+
* Coerce an arbitrary string to a valid Twitter card type.
|
|
217
|
+
* Falls back to "summary_large_image" when the value is invalid.
|
|
218
|
+
*/
|
|
219
|
+
declare function sanitizeTwitterCard(value?: string): TwitterCard;
|
|
220
|
+
/**
|
|
221
|
+
* Convert a Sanity SEO object into a structured metadata object.
|
|
222
|
+
*
|
|
223
|
+
* The return value is structurally compatible with Next.js App Router's
|
|
224
|
+
* `Metadata` type, so you can return it directly from `generateMetadata()`.
|
|
225
|
+
*
|
|
226
|
+
* @example Next.js App Router
|
|
227
|
+
* ```ts
|
|
228
|
+
* import { buildSeoMeta } from 'sanity-plugin-seofields/next'
|
|
229
|
+
* import { urlFor } from '@/sanity/lib/image'
|
|
230
|
+
*
|
|
231
|
+
* export async function generateMetadata(): Promise<Metadata> {
|
|
232
|
+
* const { seo } = await sanityFetch({ query: PAGE_SEO_QUERY })
|
|
233
|
+
* return buildSeoMeta({
|
|
234
|
+
* seo,
|
|
235
|
+
* baseUrl: process.env.NEXT_PUBLIC_SITE_URL,
|
|
236
|
+
* path: '/about',
|
|
237
|
+
* defaults: { title: 'My Site', siteName: 'My Site' },
|
|
238
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).url(),
|
|
239
|
+
* })
|
|
240
|
+
* }
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
declare function buildSeoMeta(options: BuildSeoMetaOptions): SeoMetadata;
|
|
244
|
+
/**
|
|
245
|
+
* Convert Sanity SEO fields into plain head tag data.
|
|
246
|
+
*
|
|
247
|
+
* This helper is framework-neutral: it returns serializable `title`, `meta`,
|
|
248
|
+
* and `link` arrays that can be passed to Astro layouts, Nuxt/Vue `useHead`,
|
|
249
|
+
* SvelteKit `<svelte:head>`, Remix `meta()` exports, or any custom renderer.
|
|
250
|
+
*
|
|
251
|
+
* @example Astro / Nuxt / SvelteKit
|
|
252
|
+
* ```ts
|
|
253
|
+
* import { buildSeoHead } from 'sanity-plugin-seofields/head'
|
|
254
|
+
*
|
|
255
|
+
* const head = buildSeoHead({
|
|
256
|
+
* seo: page.seo,
|
|
257
|
+
* baseUrl: 'https://example.com',
|
|
258
|
+
* path: `/blog/${page.slug}`,
|
|
259
|
+
* defaults: { title: page.title, siteName: 'My Site' },
|
|
260
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).height(630).url(),
|
|
261
|
+
* })
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
declare function buildSeoHead(options: BuildSeoMetaOptions): SeoHead;
|
|
265
|
+
|
|
266
|
+
interface LlmsLink {
|
|
267
|
+
title: string;
|
|
268
|
+
url: string;
|
|
269
|
+
description?: string;
|
|
270
|
+
}
|
|
271
|
+
interface LlmsSection {
|
|
272
|
+
title: string;
|
|
273
|
+
links: LlmsLink[];
|
|
274
|
+
}
|
|
275
|
+
interface BuildLlmsTxtOptions {
|
|
276
|
+
/** H1 title, e.g. the site name. */
|
|
277
|
+
title: string;
|
|
278
|
+
/** One-line blockquote summary rendered directly under the title. */
|
|
279
|
+
summary?: string;
|
|
280
|
+
/** Free-form Markdown prose rendered after the summary. */
|
|
281
|
+
details?: string;
|
|
282
|
+
/** Link sections rendered as `## {title}` + a bullet list. Empty sections are omitted. */
|
|
283
|
+
sections?: LlmsSection[];
|
|
284
|
+
/** Optional version, rendered in a leading `> Version: … | Updated: …` line. */
|
|
285
|
+
version?: string;
|
|
286
|
+
/** Optional "updated" label, rendered alongside `version`. */
|
|
287
|
+
updated?: string;
|
|
288
|
+
/** Prepended to any relative link URL. */
|
|
289
|
+
baseUrl?: string;
|
|
290
|
+
}
|
|
291
|
+
declare function buildLlmsTxt(options: BuildLlmsTxtOptions): string;
|
|
292
|
+
interface LlmsDoc {
|
|
293
|
+
title?: string | null;
|
|
294
|
+
slug?: {
|
|
295
|
+
current?: string | null;
|
|
296
|
+
} | string | null;
|
|
297
|
+
description?: string | null;
|
|
298
|
+
[key: string]: unknown;
|
|
299
|
+
}
|
|
300
|
+
interface DocsToLlmsSectionOptions {
|
|
301
|
+
/** Section heading. */
|
|
302
|
+
title: string;
|
|
303
|
+
/** Prepended to each document's path. */
|
|
304
|
+
baseUrl?: string;
|
|
305
|
+
/** Build the path for a document. Defaults to `/${slug}`. */
|
|
306
|
+
resolvePath?: (doc: LlmsDoc) => string | null | undefined;
|
|
307
|
+
/** Override the link title. Defaults to `doc.title`. */
|
|
308
|
+
resolveTitle?: (doc: LlmsDoc) => string | null | undefined;
|
|
309
|
+
/** Override the link description. Defaults to `doc.description`. */
|
|
310
|
+
resolveDescription?: (doc: LlmsDoc) => string | null | undefined;
|
|
311
|
+
}
|
|
312
|
+
declare function docsToLlmsSection(docs: LlmsDoc[] | null | undefined, options: DocsToLlmsSectionOptions): LlmsSection;
|
|
313
|
+
|
|
314
|
+
export { type BuildLlmsTxtOptions, type BuildSeoMetaOptions, type DocsToLlmsSectionOptions, type LlmsDoc, type LlmsLink, type LlmsSection, type SeoFieldsInput, type SeoHead, type SeoHeadLinkTag, type SeoHeadMetaTag, type SeoMetaDefaults, type SeoMetadata, buildLlmsTxt, buildSeoHead, buildSeoMeta, docsToLlmsSection, sanitizeOGType, sanitizeTwitterCard };
|
package/dist/head.d.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { a as SanityImage, b as SanityImageWithAlt } from './types-DxlPXihz.js';
|
|
2
|
+
export { B as BuildHreflangsOptions, H as HreflangLinkEntry, a as HreflangTranslation, b as buildHreflangs } from './hreflang-_VbSuWYD.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Headless CMS integration helpers for sanity-plugin-seofields
|
|
6
|
+
*
|
|
7
|
+
* Provides framework-agnostic SEO metadata utilities for use with:
|
|
8
|
+
* - Next.js App Router → buildSeoMeta() inside generateMetadata()
|
|
9
|
+
* - Next.js Pages Router → <SeoMetaTags> inside Next.js <Head>
|
|
10
|
+
* - Astro / Nuxt / Vue / SvelteKit / Remix → buildSeoHead() into native head APIs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Structured metadata returned by buildSeoMeta(). Compatible with Next.js Metadata (App Router). */
|
|
14
|
+
interface SeoMetadata {
|
|
15
|
+
title?: string | null;
|
|
16
|
+
description?: string | null;
|
|
17
|
+
keywords?: string[];
|
|
18
|
+
robots?: {
|
|
19
|
+
index?: boolean;
|
|
20
|
+
follow?: boolean;
|
|
21
|
+
notranslate?: boolean;
|
|
22
|
+
noimageindex?: boolean;
|
|
23
|
+
googleBot?: {
|
|
24
|
+
index?: boolean;
|
|
25
|
+
follow?: boolean;
|
|
26
|
+
notranslate?: boolean;
|
|
27
|
+
noimageindex?: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
openGraph?: {
|
|
31
|
+
type?: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
title?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
siteName?: string;
|
|
36
|
+
images?: Array<{
|
|
37
|
+
url: string;
|
|
38
|
+
width?: number;
|
|
39
|
+
height?: number;
|
|
40
|
+
alt?: string;
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
twitter?: {
|
|
44
|
+
card?: string;
|
|
45
|
+
site?: string;
|
|
46
|
+
creator?: string;
|
|
47
|
+
title?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
images?: string[];
|
|
50
|
+
};
|
|
51
|
+
alternates?: {
|
|
52
|
+
canonical?: string;
|
|
53
|
+
languages?: Record<string, string>;
|
|
54
|
+
};
|
|
55
|
+
/** Any custom meta attributes from seo.metaAttributes */
|
|
56
|
+
other?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
/** Plain `<meta>` tag data returned by buildSeoHead(). */
|
|
59
|
+
type SeoHeadMetaTag = {
|
|
60
|
+
name: string;
|
|
61
|
+
content: string;
|
|
62
|
+
} | {
|
|
63
|
+
property: string;
|
|
64
|
+
content: string;
|
|
65
|
+
};
|
|
66
|
+
/** Plain `<link>` tag data returned by buildSeoHead(). */
|
|
67
|
+
interface SeoHeadLinkTag {
|
|
68
|
+
rel: string;
|
|
69
|
+
href: string;
|
|
70
|
+
hreflang?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Framework-neutral head data returned by buildSeoHead().
|
|
74
|
+
*
|
|
75
|
+
* Use this in Astro, Nuxt, Vue, SvelteKit, Remix, or any frontend where you
|
|
76
|
+
* need plain values instead of React elements or Next.js Metadata.
|
|
77
|
+
*/
|
|
78
|
+
interface SeoHead {
|
|
79
|
+
title?: string | null;
|
|
80
|
+
meta: SeoHeadMetaTag[];
|
|
81
|
+
link: SeoHeadLinkTag[];
|
|
82
|
+
}
|
|
83
|
+
/** Default values used when SEO fields are missing. */
|
|
84
|
+
interface SeoMetaDefaults {
|
|
85
|
+
title?: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
siteName?: string;
|
|
88
|
+
twitterSite?: string;
|
|
89
|
+
twitterCreator?: string;
|
|
90
|
+
/** Fallback image URL when no OG / Twitter image is set. */
|
|
91
|
+
ogImage?: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Permissive image shape accepted by buildSeoMeta — compatible with both the
|
|
95
|
+
* plugin's SanityImage and Sanity's code-generated image type (where `asset`
|
|
96
|
+
* and `alt` are optional).
|
|
97
|
+
*/
|
|
98
|
+
interface SeoImageInput {
|
|
99
|
+
_type?: string;
|
|
100
|
+
asset?: {
|
|
101
|
+
_ref: string;
|
|
102
|
+
_type: string;
|
|
103
|
+
_weak?: boolean;
|
|
104
|
+
[key: string]: unknown;
|
|
105
|
+
};
|
|
106
|
+
hotspot?: unknown;
|
|
107
|
+
crop?: unknown;
|
|
108
|
+
alt?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Input-compatible variant of SeoFields. Structurally matches Sanity's
|
|
112
|
+
* code-generated types (where `asset`, `alt`, `key`, and `type` are all
|
|
113
|
+
* optional), so you can pass `data.seo` from a sanityFetch result directly
|
|
114
|
+
* without any `as any` or manual casting.
|
|
115
|
+
*/
|
|
116
|
+
interface SeoFieldsInput {
|
|
117
|
+
_type?: string;
|
|
118
|
+
robots?: {
|
|
119
|
+
noIndex?: boolean | null;
|
|
120
|
+
noFollow?: boolean | null;
|
|
121
|
+
noTranslate?: boolean | null;
|
|
122
|
+
noImageIndex?: boolean | null;
|
|
123
|
+
} | null;
|
|
124
|
+
title?: string | null;
|
|
125
|
+
description?: string | null;
|
|
126
|
+
metaImage?: SeoImageInput | null;
|
|
127
|
+
metaAttributes?: Array<{
|
|
128
|
+
_key?: string;
|
|
129
|
+
key?: string;
|
|
130
|
+
value?: string;
|
|
131
|
+
type?: string;
|
|
132
|
+
}> | null;
|
|
133
|
+
keywords?: string[] | null;
|
|
134
|
+
canonicalUrl?: string | null;
|
|
135
|
+
hreflangs?: Array<{
|
|
136
|
+
locale?: string | null;
|
|
137
|
+
url?: string | null;
|
|
138
|
+
}> | null;
|
|
139
|
+
openGraph?: {
|
|
140
|
+
_type?: string;
|
|
141
|
+
url?: string | null;
|
|
142
|
+
title?: string | null;
|
|
143
|
+
description?: string | null;
|
|
144
|
+
siteName?: string | null;
|
|
145
|
+
type?: string | null;
|
|
146
|
+
imageType?: string | null;
|
|
147
|
+
image?: SeoImageInput | null;
|
|
148
|
+
imageUrl?: string | null;
|
|
149
|
+
} | null;
|
|
150
|
+
twitter?: {
|
|
151
|
+
_type?: string;
|
|
152
|
+
card?: string | null;
|
|
153
|
+
site?: string | null;
|
|
154
|
+
creator?: string | null;
|
|
155
|
+
title?: string | null;
|
|
156
|
+
description?: string | null;
|
|
157
|
+
imageType?: string | null;
|
|
158
|
+
image?: SeoImageInput | null;
|
|
159
|
+
imageUrl?: string | null;
|
|
160
|
+
} | null;
|
|
161
|
+
}
|
|
162
|
+
/** Options accepted by buildSeoMeta(). */
|
|
163
|
+
interface BuildSeoMetaOptions {
|
|
164
|
+
/**
|
|
165
|
+
* The raw SEO object from Sanity (_type excluded or included — both work).
|
|
166
|
+
* Pass `null` or `undefined` to fall back entirely to `defaults`.
|
|
167
|
+
*
|
|
168
|
+
* Accepts both the strict plugin `SeoFields` type and Sanity's code-generated
|
|
169
|
+
* type (which has all nested fields optional) without any `as any` cast.
|
|
170
|
+
*/
|
|
171
|
+
seo?: SeoFieldsInput | null;
|
|
172
|
+
/**
|
|
173
|
+
* The base URL of your site, e.g. "https://example.com".
|
|
174
|
+
* Used for canonical URL and OpenGraph URL construction.
|
|
175
|
+
*/
|
|
176
|
+
baseUrl?: string;
|
|
177
|
+
/**
|
|
178
|
+
* The path for the current page, e.g. "/about".
|
|
179
|
+
* Combined with baseUrl to produce the canonical + OG url.
|
|
180
|
+
* Defaults to "".
|
|
181
|
+
*/
|
|
182
|
+
path?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Default values used when the Sanity SEO fields are empty / missing.
|
|
185
|
+
*/
|
|
186
|
+
defaults?: SeoMetaDefaults;
|
|
187
|
+
/**
|
|
188
|
+
* Resolve a Sanity image asset to a plain URL string.
|
|
189
|
+
*
|
|
190
|
+
* @example (using @sanity/image-url)
|
|
191
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).url()
|
|
192
|
+
*/
|
|
193
|
+
imageUrlResolver?: (image: SanityImage | SanityImageWithAlt) => string | null | undefined;
|
|
194
|
+
/**
|
|
195
|
+
* Override the hreflang alternates. When provided, this supersedes `seo.hreflangs` — pair it with
|
|
196
|
+
* `buildHreflangs()` to derive alternates from `@sanity/document-internationalization` translations.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* hreflangs: buildHreflangs(data._translations, { baseUrl })
|
|
200
|
+
*/
|
|
201
|
+
hreflangs?: Array<{
|
|
202
|
+
locale?: string | null;
|
|
203
|
+
url?: string | null;
|
|
204
|
+
}> | null;
|
|
205
|
+
}
|
|
206
|
+
declare const VALID_OG_TYPES: readonly ["website", "article", "profile", "book", "music", "video", "product"];
|
|
207
|
+
type OGType = (typeof VALID_OG_TYPES)[number];
|
|
208
|
+
/**
|
|
209
|
+
* Coerce an arbitrary string to a valid OpenGraph type.
|
|
210
|
+
* Falls back to "website" when the value is invalid.
|
|
211
|
+
*/
|
|
212
|
+
declare function sanitizeOGType(value?: string): OGType;
|
|
213
|
+
declare const VALID_TWITTER_CARDS: readonly ["summary", "summary_large_image", "app", "player"];
|
|
214
|
+
type TwitterCard = (typeof VALID_TWITTER_CARDS)[number];
|
|
215
|
+
/**
|
|
216
|
+
* Coerce an arbitrary string to a valid Twitter card type.
|
|
217
|
+
* Falls back to "summary_large_image" when the value is invalid.
|
|
218
|
+
*/
|
|
219
|
+
declare function sanitizeTwitterCard(value?: string): TwitterCard;
|
|
220
|
+
/**
|
|
221
|
+
* Convert a Sanity SEO object into a structured metadata object.
|
|
222
|
+
*
|
|
223
|
+
* The return value is structurally compatible with Next.js App Router's
|
|
224
|
+
* `Metadata` type, so you can return it directly from `generateMetadata()`.
|
|
225
|
+
*
|
|
226
|
+
* @example Next.js App Router
|
|
227
|
+
* ```ts
|
|
228
|
+
* import { buildSeoMeta } from 'sanity-plugin-seofields/next'
|
|
229
|
+
* import { urlFor } from '@/sanity/lib/image'
|
|
230
|
+
*
|
|
231
|
+
* export async function generateMetadata(): Promise<Metadata> {
|
|
232
|
+
* const { seo } = await sanityFetch({ query: PAGE_SEO_QUERY })
|
|
233
|
+
* return buildSeoMeta({
|
|
234
|
+
* seo,
|
|
235
|
+
* baseUrl: process.env.NEXT_PUBLIC_SITE_URL,
|
|
236
|
+
* path: '/about',
|
|
237
|
+
* defaults: { title: 'My Site', siteName: 'My Site' },
|
|
238
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).url(),
|
|
239
|
+
* })
|
|
240
|
+
* }
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
243
|
+
declare function buildSeoMeta(options: BuildSeoMetaOptions): SeoMetadata;
|
|
244
|
+
/**
|
|
245
|
+
* Convert Sanity SEO fields into plain head tag data.
|
|
246
|
+
*
|
|
247
|
+
* This helper is framework-neutral: it returns serializable `title`, `meta`,
|
|
248
|
+
* and `link` arrays that can be passed to Astro layouts, Nuxt/Vue `useHead`,
|
|
249
|
+
* SvelteKit `<svelte:head>`, Remix `meta()` exports, or any custom renderer.
|
|
250
|
+
*
|
|
251
|
+
* @example Astro / Nuxt / SvelteKit
|
|
252
|
+
* ```ts
|
|
253
|
+
* import { buildSeoHead } from 'sanity-plugin-seofields/head'
|
|
254
|
+
*
|
|
255
|
+
* const head = buildSeoHead({
|
|
256
|
+
* seo: page.seo,
|
|
257
|
+
* baseUrl: 'https://example.com',
|
|
258
|
+
* path: `/blog/${page.slug}`,
|
|
259
|
+
* defaults: { title: page.title, siteName: 'My Site' },
|
|
260
|
+
* imageUrlResolver: (img) => urlFor(img).width(1200).height(630).url(),
|
|
261
|
+
* })
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
declare function buildSeoHead(options: BuildSeoMetaOptions): SeoHead;
|
|
265
|
+
|
|
266
|
+
interface LlmsLink {
|
|
267
|
+
title: string;
|
|
268
|
+
url: string;
|
|
269
|
+
description?: string;
|
|
270
|
+
}
|
|
271
|
+
interface LlmsSection {
|
|
272
|
+
title: string;
|
|
273
|
+
links: LlmsLink[];
|
|
274
|
+
}
|
|
275
|
+
interface BuildLlmsTxtOptions {
|
|
276
|
+
/** H1 title, e.g. the site name. */
|
|
277
|
+
title: string;
|
|
278
|
+
/** One-line blockquote summary rendered directly under the title. */
|
|
279
|
+
summary?: string;
|
|
280
|
+
/** Free-form Markdown prose rendered after the summary. */
|
|
281
|
+
details?: string;
|
|
282
|
+
/** Link sections rendered as `## {title}` + a bullet list. Empty sections are omitted. */
|
|
283
|
+
sections?: LlmsSection[];
|
|
284
|
+
/** Optional version, rendered in a leading `> Version: … | Updated: …` line. */
|
|
285
|
+
version?: string;
|
|
286
|
+
/** Optional "updated" label, rendered alongside `version`. */
|
|
287
|
+
updated?: string;
|
|
288
|
+
/** Prepended to any relative link URL. */
|
|
289
|
+
baseUrl?: string;
|
|
290
|
+
}
|
|
291
|
+
declare function buildLlmsTxt(options: BuildLlmsTxtOptions): string;
|
|
292
|
+
interface LlmsDoc {
|
|
293
|
+
title?: string | null;
|
|
294
|
+
slug?: {
|
|
295
|
+
current?: string | null;
|
|
296
|
+
} | string | null;
|
|
297
|
+
description?: string | null;
|
|
298
|
+
[key: string]: unknown;
|
|
299
|
+
}
|
|
300
|
+
interface DocsToLlmsSectionOptions {
|
|
301
|
+
/** Section heading. */
|
|
302
|
+
title: string;
|
|
303
|
+
/** Prepended to each document's path. */
|
|
304
|
+
baseUrl?: string;
|
|
305
|
+
/** Build the path for a document. Defaults to `/${slug}`. */
|
|
306
|
+
resolvePath?: (doc: LlmsDoc) => string | null | undefined;
|
|
307
|
+
/** Override the link title. Defaults to `doc.title`. */
|
|
308
|
+
resolveTitle?: (doc: LlmsDoc) => string | null | undefined;
|
|
309
|
+
/** Override the link description. Defaults to `doc.description`. */
|
|
310
|
+
resolveDescription?: (doc: LlmsDoc) => string | null | undefined;
|
|
311
|
+
}
|
|
312
|
+
declare function docsToLlmsSection(docs: LlmsDoc[] | null | undefined, options: DocsToLlmsSectionOptions): LlmsSection;
|
|
313
|
+
|
|
314
|
+
export { type BuildLlmsTxtOptions, type BuildSeoMetaOptions, type DocsToLlmsSectionOptions, type LlmsDoc, type LlmsLink, type LlmsSection, type SeoFieldsInput, type SeoHead, type SeoHeadLinkTag, type SeoHeadMetaTag, type SeoMetaDefaults, type SeoMetadata, buildLlmsTxt, buildSeoHead, buildSeoMeta, docsToLlmsSection, sanitizeOGType, sanitizeTwitterCard };
|
package/dist/head.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildLlmsTxt,
|
|
3
|
+
buildSeoHead,
|
|
4
|
+
buildSeoMeta,
|
|
5
|
+
docsToLlmsSection,
|
|
6
|
+
sanitizeOGType,
|
|
7
|
+
sanitizeTwitterCard
|
|
8
|
+
} from "./chunk-XD4HKLEA.js";
|
|
9
|
+
import {
|
|
10
|
+
buildHreflangs
|
|
11
|
+
} from "./chunk-CRCXC45D.js";
|
|
12
|
+
import "./chunk-7N4MLTMR.js";
|
|
13
|
+
export {
|
|
14
|
+
buildHreflangs,
|
|
15
|
+
buildLlmsTxt,
|
|
16
|
+
buildSeoHead,
|
|
17
|
+
buildSeoMeta,
|
|
18
|
+
docsToLlmsSection,
|
|
19
|
+
sanitizeOGType,
|
|
20
|
+
sanitizeTwitterCard
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=head.js.map
|
package/dist/head.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface HreflangTranslation {
|
|
2
|
+
/** BCP 47 language/region tag, e.g. "en", "fr-FR". */
|
|
3
|
+
language?: string | null;
|
|
4
|
+
/** Sanity slug — either the raw string or the `{ current }` object. */
|
|
5
|
+
slug?: {
|
|
6
|
+
current?: string | null;
|
|
7
|
+
} | string | null;
|
|
8
|
+
/** Pre-built path (e.g. "/fr/about"). Wins over `slug`. */
|
|
9
|
+
path?: string | null;
|
|
10
|
+
/** Absolute URL. Wins over `baseUrl` + path. */
|
|
11
|
+
url?: string | null;
|
|
12
|
+
}
|
|
13
|
+
interface BuildHreflangsOptions {
|
|
14
|
+
/** Site origin, e.g. "https://example.com". Prepended to each translation's path. */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
/** Build the path for a translation. Defaults to `/${slug}`. Return null/undefined to skip. */
|
|
17
|
+
resolvePath?: (t: HreflangTranslation) => string | null | undefined;
|
|
18
|
+
/** Language tag to also emit as an `x-default` entry (pointing at that language's URL). */
|
|
19
|
+
xDefault?: string;
|
|
20
|
+
/** Include the current document itself in the set. */
|
|
21
|
+
current?: HreflangTranslation;
|
|
22
|
+
}
|
|
23
|
+
interface HreflangLinkEntry {
|
|
24
|
+
locale: string;
|
|
25
|
+
url: string;
|
|
26
|
+
}
|
|
27
|
+
declare function buildHreflangs(translations: HreflangTranslation[] | null | undefined, options?: BuildHreflangsOptions): HreflangLinkEntry[];
|
|
28
|
+
|
|
29
|
+
export { type BuildHreflangsOptions as B, type HreflangLinkEntry as H, type HreflangTranslation as a, buildHreflangs as b };
|