@better-seo/next 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +136 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +134 -14
- package/dist/index.js.map +1 -1
- package/package.json +15 -13
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Next.js integration for [**`@better-seo/core`**](../core/README.md): App Router
|
|
|
8
8
|
|
|
9
9
|
**Peers:** `next` **>= 14.2**, `react` **>= 18.2** (see **`package.json`**).
|
|
10
10
|
|
|
11
|
-
**Docs:** [Monorepo README](../../README.md) · [
|
|
11
|
+
**Docs:** [Monorepo README](../../README.md) · [Recipes](../../docs/recipes/) · [CONTRIBUTING](../../CONTRIBUTING.md)
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/dist/index.cjs
CHANGED
|
@@ -5,17 +5,81 @@ var core = require('@better-seo/core');
|
|
|
5
5
|
// src/register.ts
|
|
6
6
|
|
|
7
7
|
// src/to-next-metadata.ts
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
function robotsHasValueDirectives(robots) {
|
|
9
|
+
return robots.includes(":");
|
|
10
|
+
}
|
|
11
|
+
var SIMPLE_ROBOTS_TOKENS = /* @__PURE__ */ new Set([
|
|
12
|
+
"all",
|
|
13
|
+
"index",
|
|
14
|
+
"follow",
|
|
15
|
+
"noindex",
|
|
16
|
+
"nofollow",
|
|
17
|
+
"none",
|
|
18
|
+
"noarchive",
|
|
19
|
+
"nosnippet",
|
|
20
|
+
"noimageindex",
|
|
21
|
+
"notranslate",
|
|
22
|
+
"nocache",
|
|
23
|
+
"indexifembedded",
|
|
24
|
+
"nositelinkssearchbox"
|
|
25
|
+
]);
|
|
26
|
+
function robotsFromSimpleTokenList(robots) {
|
|
27
|
+
const tokens = robots.split(",").map((t) => t.trim()).filter(Boolean);
|
|
28
|
+
const lower = tokens.map((t) => t.toLowerCase());
|
|
29
|
+
for (const t of lower) {
|
|
30
|
+
if (!SIMPLE_ROBOTS_TOKENS.has(t)) {
|
|
31
|
+
return robots.trim();
|
|
32
|
+
}
|
|
14
33
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
34
|
+
let index = true;
|
|
35
|
+
let follow = true;
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const t of lower) {
|
|
38
|
+
switch (t) {
|
|
39
|
+
case "noindex":
|
|
40
|
+
index = false;
|
|
41
|
+
break;
|
|
42
|
+
case "nofollow":
|
|
43
|
+
follow = false;
|
|
44
|
+
break;
|
|
45
|
+
case "none":
|
|
46
|
+
index = false;
|
|
47
|
+
follow = false;
|
|
48
|
+
break;
|
|
49
|
+
case "noarchive":
|
|
50
|
+
out.noarchive = true;
|
|
51
|
+
break;
|
|
52
|
+
case "nosnippet":
|
|
53
|
+
out.nosnippet = true;
|
|
54
|
+
break;
|
|
55
|
+
case "noimageindex":
|
|
56
|
+
out.noimageindex = true;
|
|
57
|
+
break;
|
|
58
|
+
case "notranslate":
|
|
59
|
+
out.notranslate = true;
|
|
60
|
+
break;
|
|
61
|
+
case "nocache":
|
|
62
|
+
out.nocache = true;
|
|
63
|
+
break;
|
|
64
|
+
case "indexifembedded":
|
|
65
|
+
out.indexifembedded = true;
|
|
66
|
+
break;
|
|
67
|
+
case "nositelinkssearchbox":
|
|
68
|
+
out.nositelinkssearchbox = true;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
out.index = index;
|
|
73
|
+
out.follow = follow;
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
function metadataRobotsFromSeoString(robots) {
|
|
77
|
+
const trimmed = robots.trim();
|
|
78
|
+
if (!trimmed) return void 0;
|
|
79
|
+
if (robotsHasValueDirectives(trimmed)) {
|
|
80
|
+
return trimmed;
|
|
81
|
+
}
|
|
82
|
+
return robotsFromSimpleTokenList(trimmed);
|
|
19
83
|
}
|
|
20
84
|
function omitUndefined(o) {
|
|
21
85
|
return Object.fromEntries(
|
|
@@ -38,7 +102,29 @@ function toNextMetadata(seo2) {
|
|
|
38
102
|
m.alternates = alt;
|
|
39
103
|
}
|
|
40
104
|
if (seo2.meta.robots) {
|
|
41
|
-
m.robots =
|
|
105
|
+
m.robots = metadataRobotsFromSeoString(seo2.meta.robots);
|
|
106
|
+
}
|
|
107
|
+
if (seo2.meta.verification) {
|
|
108
|
+
const v = seo2.meta.verification;
|
|
109
|
+
const ver = omitUndefined({
|
|
110
|
+
google: v.google,
|
|
111
|
+
yahoo: v.yahoo,
|
|
112
|
+
yandex: v.yandex,
|
|
113
|
+
me: v.me,
|
|
114
|
+
...v.other && Object.keys(v.other).length > 0 ? { other: { ...v.other } } : {}
|
|
115
|
+
});
|
|
116
|
+
if (Object.keys(ver).length > 0) {
|
|
117
|
+
m.verification = ver;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (seo2.meta.pagination) {
|
|
121
|
+
const pg = omitUndefined({
|
|
122
|
+
previous: seo2.meta.pagination.previous,
|
|
123
|
+
next: seo2.meta.pagination.next
|
|
124
|
+
});
|
|
125
|
+
if (Object.keys(pg).length > 0) {
|
|
126
|
+
m.pagination = pg;
|
|
127
|
+
}
|
|
42
128
|
}
|
|
43
129
|
if (seo2.openGraph) {
|
|
44
130
|
const og = omitUndefined({
|
|
@@ -46,6 +132,14 @@ function toNextMetadata(seo2) {
|
|
|
46
132
|
description: seo2.openGraph.description,
|
|
47
133
|
url: seo2.openGraph.url,
|
|
48
134
|
type: seo2.openGraph.type,
|
|
135
|
+
siteName: seo2.openGraph.siteName,
|
|
136
|
+
locale: seo2.openGraph.locale,
|
|
137
|
+
publishedTime: seo2.openGraph.publishedTime,
|
|
138
|
+
modifiedTime: seo2.openGraph.modifiedTime,
|
|
139
|
+
expirationTime: seo2.openGraph.expirationTime,
|
|
140
|
+
authors: seo2.openGraph.authors?.length ? [...seo2.openGraph.authors] : void 0,
|
|
141
|
+
section: seo2.openGraph.section,
|
|
142
|
+
tags: seo2.openGraph.tags?.length ? [...seo2.openGraph.tags] : void 0,
|
|
49
143
|
images: seo2.openGraph.images?.map(
|
|
50
144
|
(img) => omitUndefined({
|
|
51
145
|
url: img.url,
|
|
@@ -53,7 +147,16 @@ function toNextMetadata(seo2) {
|
|
|
53
147
|
height: img.height,
|
|
54
148
|
alt: img.alt
|
|
55
149
|
})
|
|
56
|
-
)
|
|
150
|
+
),
|
|
151
|
+
videos: seo2.openGraph.videos && seo2.openGraph.videos.length > 0 ? seo2.openGraph.videos.map(
|
|
152
|
+
(v) => omitUndefined({
|
|
153
|
+
url: v.url,
|
|
154
|
+
secureUrl: v.secureUrl,
|
|
155
|
+
type: v.type,
|
|
156
|
+
width: v.width,
|
|
157
|
+
height: v.height
|
|
158
|
+
})
|
|
159
|
+
) : void 0
|
|
57
160
|
});
|
|
58
161
|
if (Object.keys(og).length > 0) {
|
|
59
162
|
m.openGraph = og;
|
|
@@ -62,6 +165,8 @@ function toNextMetadata(seo2) {
|
|
|
62
165
|
if (seo2.twitter) {
|
|
63
166
|
const tw = omitUndefined({
|
|
64
167
|
card: seo2.twitter.card,
|
|
168
|
+
site: seo2.twitter.site,
|
|
169
|
+
creator: seo2.twitter.creator,
|
|
65
170
|
title: seo2.twitter.title,
|
|
66
171
|
description: seo2.twitter.description,
|
|
67
172
|
images: seo2.twitter.image ? [seo2.twitter.image] : void 0
|
|
@@ -91,10 +196,29 @@ function prepareNextSeo(input, config) {
|
|
|
91
196
|
const doc = core.createSEO(input, config);
|
|
92
197
|
return { metadata: toNextMetadata(doc), seo: doc };
|
|
93
198
|
}
|
|
199
|
+
function seoRoute(route, input, config) {
|
|
200
|
+
const rules = config?.rules ?? [];
|
|
201
|
+
return toNextMetadata(core.createSEOForRoute(route, input, rules, config));
|
|
202
|
+
}
|
|
203
|
+
function prepareNextSeoForRoute(route, input, config) {
|
|
204
|
+
const rules = config?.rules ?? [];
|
|
205
|
+
const seo2 = core.createSEOForRoute(route, input, rules, config);
|
|
206
|
+
return { metadata: toNextMetadata(seo2), seo: seo2 };
|
|
207
|
+
}
|
|
208
|
+
function seoLayout(input, config) {
|
|
209
|
+
return core.createSEO(input, config);
|
|
210
|
+
}
|
|
211
|
+
function seoPage(parent, input, config) {
|
|
212
|
+
return withSEO(parent, input, config);
|
|
213
|
+
}
|
|
94
214
|
|
|
95
215
|
exports.mergeNextMetadataSource = mergeNextMetadataSource;
|
|
96
216
|
exports.prepareNextSeo = prepareNextSeo;
|
|
217
|
+
exports.prepareNextSeoForRoute = prepareNextSeoForRoute;
|
|
97
218
|
exports.seo = seo;
|
|
219
|
+
exports.seoLayout = seoLayout;
|
|
220
|
+
exports.seoPage = seoPage;
|
|
221
|
+
exports.seoRoute = seoRoute;
|
|
98
222
|
exports.toNextMetadata = toNextMetadata;
|
|
99
223
|
exports.withSEO = withSEO;
|
|
100
224
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/to-next-metadata.ts","../src/register.ts","../src/surface.ts"],"names":["seo","registerAdapter","createSEO","withSeoCore","mergeSEO"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Metadata } from \"next\"\nimport type { SEO } from \"@better-seo/core\"\n\nfunction robotsFromString(robots: string): Metadata[\"robots\"] {\n const lower = robots.toLowerCase()\n const noindex = lower.includes(\"noindex\")\n const nofollow = lower.includes(\"nofollow\")\n if (!noindex && !nofollow) {\n return { index: true, follow: true }\n }\n return {\n index: !noindex,\n follow: !nofollow,\n }\n}\n\nfunction omitUndefined<T extends Record<string, unknown>>(o: T): Partial<T> {\n return Object.fromEntries(\n (Object.entries(o) as [string, unknown][]).filter(([, v]) => v !== undefined),\n ) as Partial<T>\n}\n\n/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */\nexport function toNextMetadata(seo: SEO): Metadata {\n const m: Metadata = {\n title: seo.meta.title,\n }\n if (seo.meta.description !== undefined) {\n m.description = seo.meta.description\n }\n const langs = seo.meta.alternates?.languages\n const hasLang = langs !== undefined && Object.keys(langs).length > 0\n if (seo.meta.canonical || hasLang) {\n const alt: NonNullable<Metadata[\"alternates\"]> = {}\n if (seo.meta.canonical) alt.canonical = seo.meta.canonical\n if (hasLang && langs) alt.languages = { ...langs }\n m.alternates = alt\n }\n if (seo.meta.robots) {\n m.robots = robotsFromString(seo.meta.robots)\n }\n\n if (seo.openGraph) {\n const og = omitUndefined({\n title: seo.openGraph.title,\n description: seo.openGraph.description,\n url: seo.openGraph.url,\n type: seo.openGraph.type,\n images: seo.openGraph.images?.map((img) =>\n omitUndefined({\n url: img.url,\n width: img.width,\n height: img.height,\n alt: img.alt,\n }),\n ),\n })\n if (Object.keys(og).length > 0) {\n m.openGraph = og as Metadata[\"openGraph\"]\n }\n }\n\n if (seo.twitter) {\n const tw = omitUndefined({\n card: seo.twitter.card,\n title: seo.twitter.title,\n description: seo.twitter.description,\n images: seo.twitter.image ? [seo.twitter.image] : undefined,\n })\n if (Object.keys(tw).length > 0) {\n m.twitter = tw as Metadata[\"twitter\"]\n }\n }\n\n return m\n}\n","import type { Metadata } from \"next\"\nimport { registerAdapter } from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\nregisterAdapter<Metadata>({\n id: \"next\",\n toFramework: toNextMetadata,\n})\n","import type { Metadata } from \"next\"\nimport {\n createSEO,\n mergeSEO,\n type SEO,\n type SEOConfig,\n type SEOInput,\n withSEO as withSeoCore,\n} from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\n/** Voilà: `export const metadata = seo({ title: \"...\" })` (FEATURES N1). */\nexport function seo(input: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(createSEO(input, config))\n}\n\n/**\n * Layer child metadata on a parent `SEO` document (layout → page), then emit Next `Metadata`.\n */\nexport function withSEO(parent: SEO, child: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(withSeoCore(parent, child, config))\n}\n\n/** Explicit merge without `withSEO` naming (FEATURES N2). */\nexport function mergeNextMetadataSource(\n parent: SEO,\n child: SEOInput,\n config?: SEOConfig,\n): Metadata {\n return toNextMetadata(mergeSEO(parent, child, config))\n}\n\n/** One call → Next metadata + full `SEO` (for `NextJsonLd` in the same route). */\nexport function prepareNextSeo(\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const doc = createSEO(input, config)\n return { metadata: toNextMetadata(doc), seo: doc }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/to-next-metadata.ts","../src/register.ts","../src/surface.ts"],"names":["seo","registerAdapter","createSEO","withSeoCore","mergeSEO","createSEOForRoute"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Metadata } from \"next\"\nimport type { SEO } from \"@better-seo/core\"\n\n/**\n * Google / Next support comma-separated robots directives; values often use `:` (`max-snippet:20`).\n * When `:` is present, parsing is ambiguous (`unavailable_after` dates, etc.) — pass the string through\n * so Next emits the same rules as `meta name=\"robots\"`.\n */\nfunction robotsHasValueDirectives(robots: string): boolean {\n return robots.includes(\":\")\n}\n\nconst SIMPLE_ROBOTS_TOKENS = new Set([\n \"all\",\n \"index\",\n \"follow\",\n \"noindex\",\n \"nofollow\",\n \"none\",\n \"noarchive\",\n \"nosnippet\",\n \"noimageindex\",\n \"notranslate\",\n \"nocache\",\n \"indexifembedded\",\n \"nositelinkssearchbox\",\n])\n\n/**\n * Maps simple comma-separated tokens (no `:`) onto Next `Metadata.robots` object.\n * Unknown tokens fall back to raw string for safety.\n */\nfunction robotsFromSimpleTokenList(robots: string): Metadata[\"robots\"] {\n const tokens = robots\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean)\n const lower = tokens.map((t) => t.toLowerCase())\n\n for (const t of lower) {\n if (!SIMPLE_ROBOTS_TOKENS.has(t)) {\n return robots.trim()\n }\n }\n\n let index = true\n let follow = true\n const out: {\n index?: boolean\n follow?: boolean\n noarchive?: boolean\n nosnippet?: boolean\n noimageindex?: boolean\n notranslate?: boolean\n nocache?: boolean\n indexifembedded?: boolean\n nositelinkssearchbox?: boolean\n } = {}\n\n for (const t of lower) {\n switch (t) {\n case \"noindex\":\n index = false\n break\n case \"nofollow\":\n follow = false\n break\n case \"none\":\n index = false\n follow = false\n break\n case \"noarchive\":\n out.noarchive = true\n break\n case \"nosnippet\":\n out.nosnippet = true\n break\n case \"noimageindex\":\n out.noimageindex = true\n break\n case \"notranslate\":\n out.notranslate = true\n break\n case \"nocache\":\n out.nocache = true\n break\n case \"indexifembedded\":\n out.indexifembedded = true\n break\n case \"nositelinkssearchbox\":\n out.nositelinkssearchbox = true\n break\n case \"all\":\n case \"index\":\n case \"follow\":\n break\n default:\n break\n }\n }\n\n out.index = index\n out.follow = follow\n return out as Metadata[\"robots\"]\n}\n\nfunction metadataRobotsFromSeoString(robots: string): Metadata[\"robots\"] {\n const trimmed = robots.trim()\n if (!trimmed) return undefined\n\n if (robotsHasValueDirectives(trimmed)) {\n return trimmed\n }\n\n return robotsFromSimpleTokenList(trimmed)\n}\n\nfunction omitUndefined<T extends Record<string, unknown>>(o: T): Partial<T> {\n return Object.fromEntries(\n (Object.entries(o) as [string, unknown][]).filter(([, v]) => v !== undefined),\n ) as Partial<T>\n}\n\n/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */\nexport function toNextMetadata(seo: SEO): Metadata {\n const m: Metadata = {\n title: seo.meta.title,\n }\n if (seo.meta.description !== undefined) {\n m.description = seo.meta.description\n }\n const langs = seo.meta.alternates?.languages\n const hasLang = langs !== undefined && Object.keys(langs).length > 0\n if (seo.meta.canonical || hasLang) {\n const alt: NonNullable<Metadata[\"alternates\"]> = {}\n if (seo.meta.canonical) alt.canonical = seo.meta.canonical\n if (hasLang && langs) alt.languages = { ...langs }\n m.alternates = alt\n }\n if (seo.meta.robots) {\n m.robots = metadataRobotsFromSeoString(seo.meta.robots)\n }\n\n if (seo.meta.verification) {\n const v = seo.meta.verification\n const ver = omitUndefined({\n google: v.google,\n yahoo: v.yahoo,\n yandex: v.yandex,\n me: v.me,\n ...(v.other && Object.keys(v.other).length > 0 ? { other: { ...v.other } } : {}),\n })\n if (Object.keys(ver).length > 0) {\n m.verification = ver as Metadata[\"verification\"]\n }\n }\n\n if (seo.meta.pagination) {\n const pg = omitUndefined({\n previous: seo.meta.pagination.previous,\n next: seo.meta.pagination.next,\n })\n if (Object.keys(pg).length > 0) {\n m.pagination = pg as Metadata[\"pagination\"]\n }\n }\n\n if (seo.openGraph) {\n const og = omitUndefined({\n title: seo.openGraph.title,\n description: seo.openGraph.description,\n url: seo.openGraph.url,\n type: seo.openGraph.type,\n siteName: seo.openGraph.siteName,\n locale: seo.openGraph.locale,\n publishedTime: seo.openGraph.publishedTime,\n modifiedTime: seo.openGraph.modifiedTime,\n expirationTime: seo.openGraph.expirationTime,\n authors: seo.openGraph.authors?.length ? [...seo.openGraph.authors] : undefined,\n section: seo.openGraph.section,\n tags: seo.openGraph.tags?.length ? [...seo.openGraph.tags] : undefined,\n images: seo.openGraph.images?.map((img) =>\n omitUndefined({\n url: img.url,\n width: img.width,\n height: img.height,\n alt: img.alt,\n }),\n ),\n videos:\n seo.openGraph.videos && seo.openGraph.videos.length > 0\n ? seo.openGraph.videos.map((v) =>\n omitUndefined({\n url: v.url,\n secureUrl: v.secureUrl,\n type: v.type,\n width: v.width,\n height: v.height,\n }),\n )\n : undefined,\n })\n if (Object.keys(og).length > 0) {\n m.openGraph = og as Metadata[\"openGraph\"]\n }\n }\n\n if (seo.twitter) {\n const tw = omitUndefined({\n card: seo.twitter.card,\n site: seo.twitter.site,\n creator: seo.twitter.creator,\n title: seo.twitter.title,\n description: seo.twitter.description,\n images: seo.twitter.image ? [seo.twitter.image] : undefined,\n })\n if (Object.keys(tw).length > 0) {\n m.twitter = tw as Metadata[\"twitter\"]\n }\n }\n\n return m\n}\n","import type { Metadata } from \"next\"\nimport { registerAdapter } from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\nregisterAdapter<Metadata>({\n id: \"next\",\n toFramework: toNextMetadata,\n})\n","import type { Metadata } from \"next\"\nimport {\n createSEO,\n createSEOForRoute,\n mergeSEO,\n type SEO,\n type SEOConfig,\n type SEOInput,\n withSEO as withSeoCore,\n} from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\n/** Voilà: `export const metadata = seo({ title: \"...\" })` (FEATURES N1). */\nexport function seo(input: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(createSEO(input, config))\n}\n\n/**\n * Layer child metadata on a parent `SEO` document (layout → page), then emit Next `Metadata`.\n */\nexport function withSEO(parent: SEO, child: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(withSeoCore(parent, child, config))\n}\n\n/** Explicit merge without `withSEO` naming (FEATURES N2). */\nexport function mergeNextMetadataSource(\n parent: SEO,\n child: SEOInput,\n config?: SEOConfig,\n): Metadata {\n return toNextMetadata(mergeSEO(parent, child, config))\n}\n\n/** One call → Next metadata + full `SEO` (for `NextJsonLd` in the same route). */\nexport function prepareNextSeo(\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const doc = createSEO(input, config)\n return { metadata: toNextMetadata(doc), seo: doc }\n}\n\n/** V5 — Next `Metadata` with {@link SEOConfig.rules} applied for an explicit pathname (N9). */\nexport function seoRoute(route: string, input: SEOInput, config?: SEOConfig): Metadata {\n const rules = config?.rules ?? []\n return toNextMetadata(createSEOForRoute(route, input, rules, config))\n}\n\n/** Like {@link prepareNextSeo}, but merges route rules from `config.rules` first. */\nexport function prepareNextSeoForRoute(\n route: string,\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const rules = config?.rules ?? []\n const seo = createSEOForRoute(route, input, rules, config)\n return { metadata: toNextMetadata(seo), seo }\n}\n\n/** V4 — layout defaults as canonical parent `SEO` (alias of `createSEO` for voilà naming). */\nexport function seoLayout(input: SEOInput, config?: SEOConfig): SEO {\n return createSEO(input, config)\n}\n\n/** V4 — page `Metadata` layered on layout `SEO` (same as {@link withSEO}). */\nexport function seoPage(parent: SEO, input: SEOInput, config?: SEOConfig): Metadata {\n return withSEO(parent, input, config)\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -14,8 +14,19 @@ declare function prepareNextSeo(input: SEOInput, config?: SEOConfig): {
|
|
|
14
14
|
readonly metadata: Metadata;
|
|
15
15
|
readonly seo: SEO;
|
|
16
16
|
};
|
|
17
|
+
/** V5 — Next `Metadata` with {@link SEOConfig.rules} applied for an explicit pathname (N9). */
|
|
18
|
+
declare function seoRoute(route: string, input: SEOInput, config?: SEOConfig): Metadata;
|
|
19
|
+
/** Like {@link prepareNextSeo}, but merges route rules from `config.rules` first. */
|
|
20
|
+
declare function prepareNextSeoForRoute(route: string, input: SEOInput, config?: SEOConfig): {
|
|
21
|
+
readonly metadata: Metadata;
|
|
22
|
+
readonly seo: SEO;
|
|
23
|
+
};
|
|
24
|
+
/** V4 — layout defaults as canonical parent `SEO` (alias of `createSEO` for voilà naming). */
|
|
25
|
+
declare function seoLayout(input: SEOInput, config?: SEOConfig): SEO;
|
|
26
|
+
/** V4 — page `Metadata` layered on layout `SEO` (same as {@link withSEO}). */
|
|
27
|
+
declare function seoPage(parent: SEO, input: SEOInput, config?: SEOConfig): Metadata;
|
|
17
28
|
|
|
18
29
|
/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */
|
|
19
30
|
declare function toNextMetadata(seo: SEO): Metadata;
|
|
20
31
|
|
|
21
|
-
export { mergeNextMetadataSource, prepareNextSeo, seo, toNextMetadata, withSEO };
|
|
32
|
+
export { mergeNextMetadataSource, prepareNextSeo, prepareNextSeoForRoute, seo, seoLayout, seoPage, seoRoute, toNextMetadata, withSEO };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,8 +14,19 @@ declare function prepareNextSeo(input: SEOInput, config?: SEOConfig): {
|
|
|
14
14
|
readonly metadata: Metadata;
|
|
15
15
|
readonly seo: SEO;
|
|
16
16
|
};
|
|
17
|
+
/** V5 — Next `Metadata` with {@link SEOConfig.rules} applied for an explicit pathname (N9). */
|
|
18
|
+
declare function seoRoute(route: string, input: SEOInput, config?: SEOConfig): Metadata;
|
|
19
|
+
/** Like {@link prepareNextSeo}, but merges route rules from `config.rules` first. */
|
|
20
|
+
declare function prepareNextSeoForRoute(route: string, input: SEOInput, config?: SEOConfig): {
|
|
21
|
+
readonly metadata: Metadata;
|
|
22
|
+
readonly seo: SEO;
|
|
23
|
+
};
|
|
24
|
+
/** V4 — layout defaults as canonical parent `SEO` (alias of `createSEO` for voilà naming). */
|
|
25
|
+
declare function seoLayout(input: SEOInput, config?: SEOConfig): SEO;
|
|
26
|
+
/** V4 — page `Metadata` layered on layout `SEO` (same as {@link withSEO}). */
|
|
27
|
+
declare function seoPage(parent: SEO, input: SEOInput, config?: SEOConfig): Metadata;
|
|
17
28
|
|
|
18
29
|
/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */
|
|
19
30
|
declare function toNextMetadata(seo: SEO): Metadata;
|
|
20
31
|
|
|
21
|
-
export { mergeNextMetadataSource, prepareNextSeo, seo, toNextMetadata, withSEO };
|
|
32
|
+
export { mergeNextMetadataSource, prepareNextSeo, prepareNextSeoForRoute, seo, seoLayout, seoPage, seoRoute, toNextMetadata, withSEO };
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,83 @@
|
|
|
1
|
-
import { registerAdapter, createSEO, withSEO as withSEO$1, mergeSEO } from '@better-seo/core';
|
|
1
|
+
import { registerAdapter, createSEO, withSEO as withSEO$1, mergeSEO, createSEOForRoute } from '@better-seo/core';
|
|
2
2
|
|
|
3
3
|
// src/register.ts
|
|
4
4
|
|
|
5
5
|
// src/to-next-metadata.ts
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
function robotsHasValueDirectives(robots) {
|
|
7
|
+
return robots.includes(":");
|
|
8
|
+
}
|
|
9
|
+
var SIMPLE_ROBOTS_TOKENS = /* @__PURE__ */ new Set([
|
|
10
|
+
"all",
|
|
11
|
+
"index",
|
|
12
|
+
"follow",
|
|
13
|
+
"noindex",
|
|
14
|
+
"nofollow",
|
|
15
|
+
"none",
|
|
16
|
+
"noarchive",
|
|
17
|
+
"nosnippet",
|
|
18
|
+
"noimageindex",
|
|
19
|
+
"notranslate",
|
|
20
|
+
"nocache",
|
|
21
|
+
"indexifembedded",
|
|
22
|
+
"nositelinkssearchbox"
|
|
23
|
+
]);
|
|
24
|
+
function robotsFromSimpleTokenList(robots) {
|
|
25
|
+
const tokens = robots.split(",").map((t) => t.trim()).filter(Boolean);
|
|
26
|
+
const lower = tokens.map((t) => t.toLowerCase());
|
|
27
|
+
for (const t of lower) {
|
|
28
|
+
if (!SIMPLE_ROBOTS_TOKENS.has(t)) {
|
|
29
|
+
return robots.trim();
|
|
30
|
+
}
|
|
12
31
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
let index = true;
|
|
33
|
+
let follow = true;
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const t of lower) {
|
|
36
|
+
switch (t) {
|
|
37
|
+
case "noindex":
|
|
38
|
+
index = false;
|
|
39
|
+
break;
|
|
40
|
+
case "nofollow":
|
|
41
|
+
follow = false;
|
|
42
|
+
break;
|
|
43
|
+
case "none":
|
|
44
|
+
index = false;
|
|
45
|
+
follow = false;
|
|
46
|
+
break;
|
|
47
|
+
case "noarchive":
|
|
48
|
+
out.noarchive = true;
|
|
49
|
+
break;
|
|
50
|
+
case "nosnippet":
|
|
51
|
+
out.nosnippet = true;
|
|
52
|
+
break;
|
|
53
|
+
case "noimageindex":
|
|
54
|
+
out.noimageindex = true;
|
|
55
|
+
break;
|
|
56
|
+
case "notranslate":
|
|
57
|
+
out.notranslate = true;
|
|
58
|
+
break;
|
|
59
|
+
case "nocache":
|
|
60
|
+
out.nocache = true;
|
|
61
|
+
break;
|
|
62
|
+
case "indexifembedded":
|
|
63
|
+
out.indexifembedded = true;
|
|
64
|
+
break;
|
|
65
|
+
case "nositelinkssearchbox":
|
|
66
|
+
out.nositelinkssearchbox = true;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
out.index = index;
|
|
71
|
+
out.follow = follow;
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
function metadataRobotsFromSeoString(robots) {
|
|
75
|
+
const trimmed = robots.trim();
|
|
76
|
+
if (!trimmed) return void 0;
|
|
77
|
+
if (robotsHasValueDirectives(trimmed)) {
|
|
78
|
+
return trimmed;
|
|
79
|
+
}
|
|
80
|
+
return robotsFromSimpleTokenList(trimmed);
|
|
17
81
|
}
|
|
18
82
|
function omitUndefined(o) {
|
|
19
83
|
return Object.fromEntries(
|
|
@@ -36,7 +100,29 @@ function toNextMetadata(seo2) {
|
|
|
36
100
|
m.alternates = alt;
|
|
37
101
|
}
|
|
38
102
|
if (seo2.meta.robots) {
|
|
39
|
-
m.robots =
|
|
103
|
+
m.robots = metadataRobotsFromSeoString(seo2.meta.robots);
|
|
104
|
+
}
|
|
105
|
+
if (seo2.meta.verification) {
|
|
106
|
+
const v = seo2.meta.verification;
|
|
107
|
+
const ver = omitUndefined({
|
|
108
|
+
google: v.google,
|
|
109
|
+
yahoo: v.yahoo,
|
|
110
|
+
yandex: v.yandex,
|
|
111
|
+
me: v.me,
|
|
112
|
+
...v.other && Object.keys(v.other).length > 0 ? { other: { ...v.other } } : {}
|
|
113
|
+
});
|
|
114
|
+
if (Object.keys(ver).length > 0) {
|
|
115
|
+
m.verification = ver;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (seo2.meta.pagination) {
|
|
119
|
+
const pg = omitUndefined({
|
|
120
|
+
previous: seo2.meta.pagination.previous,
|
|
121
|
+
next: seo2.meta.pagination.next
|
|
122
|
+
});
|
|
123
|
+
if (Object.keys(pg).length > 0) {
|
|
124
|
+
m.pagination = pg;
|
|
125
|
+
}
|
|
40
126
|
}
|
|
41
127
|
if (seo2.openGraph) {
|
|
42
128
|
const og = omitUndefined({
|
|
@@ -44,6 +130,14 @@ function toNextMetadata(seo2) {
|
|
|
44
130
|
description: seo2.openGraph.description,
|
|
45
131
|
url: seo2.openGraph.url,
|
|
46
132
|
type: seo2.openGraph.type,
|
|
133
|
+
siteName: seo2.openGraph.siteName,
|
|
134
|
+
locale: seo2.openGraph.locale,
|
|
135
|
+
publishedTime: seo2.openGraph.publishedTime,
|
|
136
|
+
modifiedTime: seo2.openGraph.modifiedTime,
|
|
137
|
+
expirationTime: seo2.openGraph.expirationTime,
|
|
138
|
+
authors: seo2.openGraph.authors?.length ? [...seo2.openGraph.authors] : void 0,
|
|
139
|
+
section: seo2.openGraph.section,
|
|
140
|
+
tags: seo2.openGraph.tags?.length ? [...seo2.openGraph.tags] : void 0,
|
|
47
141
|
images: seo2.openGraph.images?.map(
|
|
48
142
|
(img) => omitUndefined({
|
|
49
143
|
url: img.url,
|
|
@@ -51,7 +145,16 @@ function toNextMetadata(seo2) {
|
|
|
51
145
|
height: img.height,
|
|
52
146
|
alt: img.alt
|
|
53
147
|
})
|
|
54
|
-
)
|
|
148
|
+
),
|
|
149
|
+
videos: seo2.openGraph.videos && seo2.openGraph.videos.length > 0 ? seo2.openGraph.videos.map(
|
|
150
|
+
(v) => omitUndefined({
|
|
151
|
+
url: v.url,
|
|
152
|
+
secureUrl: v.secureUrl,
|
|
153
|
+
type: v.type,
|
|
154
|
+
width: v.width,
|
|
155
|
+
height: v.height
|
|
156
|
+
})
|
|
157
|
+
) : void 0
|
|
55
158
|
});
|
|
56
159
|
if (Object.keys(og).length > 0) {
|
|
57
160
|
m.openGraph = og;
|
|
@@ -60,6 +163,8 @@ function toNextMetadata(seo2) {
|
|
|
60
163
|
if (seo2.twitter) {
|
|
61
164
|
const tw = omitUndefined({
|
|
62
165
|
card: seo2.twitter.card,
|
|
166
|
+
site: seo2.twitter.site,
|
|
167
|
+
creator: seo2.twitter.creator,
|
|
63
168
|
title: seo2.twitter.title,
|
|
64
169
|
description: seo2.twitter.description,
|
|
65
170
|
images: seo2.twitter.image ? [seo2.twitter.image] : void 0
|
|
@@ -89,7 +194,22 @@ function prepareNextSeo(input, config) {
|
|
|
89
194
|
const doc = createSEO(input, config);
|
|
90
195
|
return { metadata: toNextMetadata(doc), seo: doc };
|
|
91
196
|
}
|
|
197
|
+
function seoRoute(route, input, config) {
|
|
198
|
+
const rules = config?.rules ?? [];
|
|
199
|
+
return toNextMetadata(createSEOForRoute(route, input, rules, config));
|
|
200
|
+
}
|
|
201
|
+
function prepareNextSeoForRoute(route, input, config) {
|
|
202
|
+
const rules = config?.rules ?? [];
|
|
203
|
+
const seo2 = createSEOForRoute(route, input, rules, config);
|
|
204
|
+
return { metadata: toNextMetadata(seo2), seo: seo2 };
|
|
205
|
+
}
|
|
206
|
+
function seoLayout(input, config) {
|
|
207
|
+
return createSEO(input, config);
|
|
208
|
+
}
|
|
209
|
+
function seoPage(parent, input, config) {
|
|
210
|
+
return withSEO(parent, input, config);
|
|
211
|
+
}
|
|
92
212
|
|
|
93
|
-
export { mergeNextMetadataSource, prepareNextSeo, seo, toNextMetadata, withSEO };
|
|
213
|
+
export { mergeNextMetadataSource, prepareNextSeo, prepareNextSeoForRoute, seo, seoLayout, seoPage, seoRoute, toNextMetadata, withSEO };
|
|
94
214
|
//# sourceMappingURL=index.js.map
|
|
95
215
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/to-next-metadata.ts","../src/register.ts","../src/surface.ts"],"names":["seo","withSeoCore"],"mappings":"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","file":"index.js","sourcesContent":["import type { Metadata } from \"next\"\nimport type { SEO } from \"@better-seo/core\"\n\nfunction robotsFromString(robots: string): Metadata[\"robots\"] {\n const lower = robots.toLowerCase()\n const noindex = lower.includes(\"noindex\")\n const nofollow = lower.includes(\"nofollow\")\n if (!noindex && !nofollow) {\n return { index: true, follow: true }\n }\n return {\n index: !noindex,\n follow: !nofollow,\n }\n}\n\nfunction omitUndefined<T extends Record<string, unknown>>(o: T): Partial<T> {\n return Object.fromEntries(\n (Object.entries(o) as [string, unknown][]).filter(([, v]) => v !== undefined),\n ) as Partial<T>\n}\n\n/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */\nexport function toNextMetadata(seo: SEO): Metadata {\n const m: Metadata = {\n title: seo.meta.title,\n }\n if (seo.meta.description !== undefined) {\n m.description = seo.meta.description\n }\n const langs = seo.meta.alternates?.languages\n const hasLang = langs !== undefined && Object.keys(langs).length > 0\n if (seo.meta.canonical || hasLang) {\n const alt: NonNullable<Metadata[\"alternates\"]> = {}\n if (seo.meta.canonical) alt.canonical = seo.meta.canonical\n if (hasLang && langs) alt.languages = { ...langs }\n m.alternates = alt\n }\n if (seo.meta.robots) {\n m.robots = robotsFromString(seo.meta.robots)\n }\n\n if (seo.openGraph) {\n const og = omitUndefined({\n title: seo.openGraph.title,\n description: seo.openGraph.description,\n url: seo.openGraph.url,\n type: seo.openGraph.type,\n images: seo.openGraph.images?.map((img) =>\n omitUndefined({\n url: img.url,\n width: img.width,\n height: img.height,\n alt: img.alt,\n }),\n ),\n })\n if (Object.keys(og).length > 0) {\n m.openGraph = og as Metadata[\"openGraph\"]\n }\n }\n\n if (seo.twitter) {\n const tw = omitUndefined({\n card: seo.twitter.card,\n title: seo.twitter.title,\n description: seo.twitter.description,\n images: seo.twitter.image ? [seo.twitter.image] : undefined,\n })\n if (Object.keys(tw).length > 0) {\n m.twitter = tw as Metadata[\"twitter\"]\n }\n }\n\n return m\n}\n","import type { Metadata } from \"next\"\nimport { registerAdapter } from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\nregisterAdapter<Metadata>({\n id: \"next\",\n toFramework: toNextMetadata,\n})\n","import type { Metadata } from \"next\"\nimport {\n createSEO,\n mergeSEO,\n type SEO,\n type SEOConfig,\n type SEOInput,\n withSEO as withSeoCore,\n} from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\n/** Voilà: `export const metadata = seo({ title: \"...\" })` (FEATURES N1). */\nexport function seo(input: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(createSEO(input, config))\n}\n\n/**\n * Layer child metadata on a parent `SEO` document (layout → page), then emit Next `Metadata`.\n */\nexport function withSEO(parent: SEO, child: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(withSeoCore(parent, child, config))\n}\n\n/** Explicit merge without `withSEO` naming (FEATURES N2). */\nexport function mergeNextMetadataSource(\n parent: SEO,\n child: SEOInput,\n config?: SEOConfig,\n): Metadata {\n return toNextMetadata(mergeSEO(parent, child, config))\n}\n\n/** One call → Next metadata + full `SEO` (for `NextJsonLd` in the same route). */\nexport function prepareNextSeo(\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const doc = createSEO(input, config)\n return { metadata: toNextMetadata(doc), seo: doc }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/to-next-metadata.ts","../src/register.ts","../src/surface.ts"],"names":["seo","withSeoCore"],"mappings":"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","file":"index.js","sourcesContent":["import type { Metadata } from \"next\"\nimport type { SEO } from \"@better-seo/core\"\n\n/**\n * Google / Next support comma-separated robots directives; values often use `:` (`max-snippet:20`).\n * When `:` is present, parsing is ambiguous (`unavailable_after` dates, etc.) — pass the string through\n * so Next emits the same rules as `meta name=\"robots\"`.\n */\nfunction robotsHasValueDirectives(robots: string): boolean {\n return robots.includes(\":\")\n}\n\nconst SIMPLE_ROBOTS_TOKENS = new Set([\n \"all\",\n \"index\",\n \"follow\",\n \"noindex\",\n \"nofollow\",\n \"none\",\n \"noarchive\",\n \"nosnippet\",\n \"noimageindex\",\n \"notranslate\",\n \"nocache\",\n \"indexifembedded\",\n \"nositelinkssearchbox\",\n])\n\n/**\n * Maps simple comma-separated tokens (no `:`) onto Next `Metadata.robots` object.\n * Unknown tokens fall back to raw string for safety.\n */\nfunction robotsFromSimpleTokenList(robots: string): Metadata[\"robots\"] {\n const tokens = robots\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean)\n const lower = tokens.map((t) => t.toLowerCase())\n\n for (const t of lower) {\n if (!SIMPLE_ROBOTS_TOKENS.has(t)) {\n return robots.trim()\n }\n }\n\n let index = true\n let follow = true\n const out: {\n index?: boolean\n follow?: boolean\n noarchive?: boolean\n nosnippet?: boolean\n noimageindex?: boolean\n notranslate?: boolean\n nocache?: boolean\n indexifembedded?: boolean\n nositelinkssearchbox?: boolean\n } = {}\n\n for (const t of lower) {\n switch (t) {\n case \"noindex\":\n index = false\n break\n case \"nofollow\":\n follow = false\n break\n case \"none\":\n index = false\n follow = false\n break\n case \"noarchive\":\n out.noarchive = true\n break\n case \"nosnippet\":\n out.nosnippet = true\n break\n case \"noimageindex\":\n out.noimageindex = true\n break\n case \"notranslate\":\n out.notranslate = true\n break\n case \"nocache\":\n out.nocache = true\n break\n case \"indexifembedded\":\n out.indexifembedded = true\n break\n case \"nositelinkssearchbox\":\n out.nositelinkssearchbox = true\n break\n case \"all\":\n case \"index\":\n case \"follow\":\n break\n default:\n break\n }\n }\n\n out.index = index\n out.follow = follow\n return out as Metadata[\"robots\"]\n}\n\nfunction metadataRobotsFromSeoString(robots: string): Metadata[\"robots\"] {\n const trimmed = robots.trim()\n if (!trimmed) return undefined\n\n if (robotsHasValueDirectives(trimmed)) {\n return trimmed\n }\n\n return robotsFromSimpleTokenList(trimmed)\n}\n\nfunction omitUndefined<T extends Record<string, unknown>>(o: T): Partial<T> {\n return Object.fromEntries(\n (Object.entries(o) as [string, unknown][]).filter(([, v]) => v !== undefined),\n ) as Partial<T>\n}\n\n/** Map normalized `SEO` → Next.js `Metadata` (App Router). JSON-LD is not included — use `@better-seo/next/json-ld`. */\nexport function toNextMetadata(seo: SEO): Metadata {\n const m: Metadata = {\n title: seo.meta.title,\n }\n if (seo.meta.description !== undefined) {\n m.description = seo.meta.description\n }\n const langs = seo.meta.alternates?.languages\n const hasLang = langs !== undefined && Object.keys(langs).length > 0\n if (seo.meta.canonical || hasLang) {\n const alt: NonNullable<Metadata[\"alternates\"]> = {}\n if (seo.meta.canonical) alt.canonical = seo.meta.canonical\n if (hasLang && langs) alt.languages = { ...langs }\n m.alternates = alt\n }\n if (seo.meta.robots) {\n m.robots = metadataRobotsFromSeoString(seo.meta.robots)\n }\n\n if (seo.meta.verification) {\n const v = seo.meta.verification\n const ver = omitUndefined({\n google: v.google,\n yahoo: v.yahoo,\n yandex: v.yandex,\n me: v.me,\n ...(v.other && Object.keys(v.other).length > 0 ? { other: { ...v.other } } : {}),\n })\n if (Object.keys(ver).length > 0) {\n m.verification = ver as Metadata[\"verification\"]\n }\n }\n\n if (seo.meta.pagination) {\n const pg = omitUndefined({\n previous: seo.meta.pagination.previous,\n next: seo.meta.pagination.next,\n })\n if (Object.keys(pg).length > 0) {\n m.pagination = pg as Metadata[\"pagination\"]\n }\n }\n\n if (seo.openGraph) {\n const og = omitUndefined({\n title: seo.openGraph.title,\n description: seo.openGraph.description,\n url: seo.openGraph.url,\n type: seo.openGraph.type,\n siteName: seo.openGraph.siteName,\n locale: seo.openGraph.locale,\n publishedTime: seo.openGraph.publishedTime,\n modifiedTime: seo.openGraph.modifiedTime,\n expirationTime: seo.openGraph.expirationTime,\n authors: seo.openGraph.authors?.length ? [...seo.openGraph.authors] : undefined,\n section: seo.openGraph.section,\n tags: seo.openGraph.tags?.length ? [...seo.openGraph.tags] : undefined,\n images: seo.openGraph.images?.map((img) =>\n omitUndefined({\n url: img.url,\n width: img.width,\n height: img.height,\n alt: img.alt,\n }),\n ),\n videos:\n seo.openGraph.videos && seo.openGraph.videos.length > 0\n ? seo.openGraph.videos.map((v) =>\n omitUndefined({\n url: v.url,\n secureUrl: v.secureUrl,\n type: v.type,\n width: v.width,\n height: v.height,\n }),\n )\n : undefined,\n })\n if (Object.keys(og).length > 0) {\n m.openGraph = og as Metadata[\"openGraph\"]\n }\n }\n\n if (seo.twitter) {\n const tw = omitUndefined({\n card: seo.twitter.card,\n site: seo.twitter.site,\n creator: seo.twitter.creator,\n title: seo.twitter.title,\n description: seo.twitter.description,\n images: seo.twitter.image ? [seo.twitter.image] : undefined,\n })\n if (Object.keys(tw).length > 0) {\n m.twitter = tw as Metadata[\"twitter\"]\n }\n }\n\n return m\n}\n","import type { Metadata } from \"next\"\nimport { registerAdapter } from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\nregisterAdapter<Metadata>({\n id: \"next\",\n toFramework: toNextMetadata,\n})\n","import type { Metadata } from \"next\"\nimport {\n createSEO,\n createSEOForRoute,\n mergeSEO,\n type SEO,\n type SEOConfig,\n type SEOInput,\n withSEO as withSeoCore,\n} from \"@better-seo/core\"\nimport { toNextMetadata } from \"./to-next-metadata.js\"\n\n/** Voilà: `export const metadata = seo({ title: \"...\" })` (FEATURES N1). */\nexport function seo(input: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(createSEO(input, config))\n}\n\n/**\n * Layer child metadata on a parent `SEO` document (layout → page), then emit Next `Metadata`.\n */\nexport function withSEO(parent: SEO, child: SEOInput, config?: SEOConfig): Metadata {\n return toNextMetadata(withSeoCore(parent, child, config))\n}\n\n/** Explicit merge without `withSEO` naming (FEATURES N2). */\nexport function mergeNextMetadataSource(\n parent: SEO,\n child: SEOInput,\n config?: SEOConfig,\n): Metadata {\n return toNextMetadata(mergeSEO(parent, child, config))\n}\n\n/** One call → Next metadata + full `SEO` (for `NextJsonLd` in the same route). */\nexport function prepareNextSeo(\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const doc = createSEO(input, config)\n return { metadata: toNextMetadata(doc), seo: doc }\n}\n\n/** V5 — Next `Metadata` with {@link SEOConfig.rules} applied for an explicit pathname (N9). */\nexport function seoRoute(route: string, input: SEOInput, config?: SEOConfig): Metadata {\n const rules = config?.rules ?? []\n return toNextMetadata(createSEOForRoute(route, input, rules, config))\n}\n\n/** Like {@link prepareNextSeo}, but merges route rules from `config.rules` first. */\nexport function prepareNextSeoForRoute(\n route: string,\n input: SEOInput,\n config?: SEOConfig,\n): { readonly metadata: Metadata; readonly seo: SEO } {\n const rules = config?.rules ?? []\n const seo = createSEOForRoute(route, input, rules, config)\n return { metadata: toNextMetadata(seo), seo }\n}\n\n/** V4 — layout defaults as canonical parent `SEO` (alias of `createSEO` for voilà naming). */\nexport function seoLayout(input: SEOInput, config?: SEOConfig): SEO {\n return createSEO(input, config)\n}\n\n/** V4 — page `Metadata` layered on layout `SEO` (same as {@link withSEO}). */\nexport function seoPage(parent: SEO, input: SEOInput, config?: SEOConfig): Metadata {\n return withSEO(parent, input, config)\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-seo/next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Next.js integration for @better-seo/core on the App Router (and documented Pages Router patterns): turn your SEO model into Metadata and generateMetadata, use shorthand helpers like seo() and prepareNextSeo, merge layout and page SEO without duplicating logic, and stream JSON-LD through NextJsonLd from @better-seo/next/json-ld so structured data uses the same serializeJSONLD path as everywhere else. Peer dependencies: next >= 14.2 and react >= 18.2.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@better-seo/core": "0.0.
|
|
27
|
+
"@better-seo/core": "0.0.2"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"next": ">=14.2.0",
|
|
@@ -36,24 +36,26 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
|
-
"build": "tsup",
|
|
40
|
-
"test": "vitest run",
|
|
41
|
-
"test:coverage": "vitest run --coverage",
|
|
42
|
-
"lint": "eslint .",
|
|
43
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
39
|
+
"build": "node ../../scripts/run-tsup.mjs",
|
|
40
|
+
"test": "npm exec -- vitest run",
|
|
41
|
+
"test:coverage": "npm exec -- vitest run --coverage",
|
|
42
|
+
"lint": "npm exec -- eslint .",
|
|
43
|
+
"typecheck": "npm exec -- tsc -p tsconfig.json --noEmit",
|
|
44
44
|
"audit": "npm audit --audit-level=high"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
|
-
"node": ">=
|
|
50
|
+
"node": ">=24.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/react": "
|
|
54
|
-
"@vitest/coverage-v8": "
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
53
|
+
"@types/react": "19.2.14",
|
|
54
|
+
"@vitest/coverage-v8": "4.1.2",
|
|
55
|
+
"next": "16.2.2",
|
|
56
|
+
"react": "19.2.4",
|
|
57
|
+
"tsup": "8.5.1",
|
|
58
|
+
"typescript": "6.0.2",
|
|
59
|
+
"vitest": "4.1.2"
|
|
58
60
|
}
|
|
59
61
|
}
|