@better-seo/core 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 +390 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -7
- package/dist/index.d.ts +106 -7
- package/dist/index.js +385 -59
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +1021 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +21 -0
- package/dist/node.d.ts +21 -0
- package/dist/node.js +980 -0
- package/dist/node.js.map +1 -0
- package/package.json +18 -12
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,29 @@ interface SEOPlugin {
|
|
|
20
20
|
readonly afterMerge?: (seo: SEO, ctx: {
|
|
21
21
|
readonly config?: SEOConfig;
|
|
22
22
|
}) => SEO;
|
|
23
|
+
/**
|
|
24
|
+
* Runs after built-in `renderTags` output; only invoked when `renderTags(seo, config)` is called with `config` (plugins come from `config.plugins`).
|
|
25
|
+
*/
|
|
26
|
+
readonly onRenderTags?: (tags: readonly TagDescriptor[], ctx: {
|
|
27
|
+
readonly seo: SEO;
|
|
28
|
+
readonly config?: SEOConfig;
|
|
29
|
+
}) => readonly TagDescriptor[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Search-console verification tokens (aligned with Next.js `Metadata.verification`).
|
|
33
|
+
* Renders `<meta name="…" content="…">` via {@link renderTags}.
|
|
34
|
+
*/
|
|
35
|
+
interface SEOVerification {
|
|
36
|
+
readonly google?: string;
|
|
37
|
+
readonly yahoo?: string;
|
|
38
|
+
readonly yandex?: string;
|
|
39
|
+
readonly me?: string;
|
|
40
|
+
readonly other?: Readonly<Record<string, string>>;
|
|
41
|
+
}
|
|
42
|
+
/** Pagination `rel="prev"` / `rel="next"` (aligned with Next.js `Metadata.pagination`). */
|
|
43
|
+
interface SEOPagination {
|
|
44
|
+
readonly previous?: string;
|
|
45
|
+
readonly next?: string;
|
|
23
46
|
}
|
|
24
47
|
interface SEOConfig {
|
|
25
48
|
readonly titleTemplate?: string;
|
|
@@ -34,6 +57,11 @@ interface SEOConfig {
|
|
|
34
57
|
}>;
|
|
35
58
|
/** Hooks run in order; prefer `createSEOContext` for request-scoped registration (future hardening). */
|
|
36
59
|
readonly plugins?: readonly SEOPlugin[];
|
|
60
|
+
/**
|
|
61
|
+
* Route → partial input via {@link applyRules} / {@link createSEOForRoute} / {@link seoRoute} (Wave 6 / N9).
|
|
62
|
+
* Ignored by plain `createSEO` — use route-aware APIs when you need rules applied.
|
|
63
|
+
*/
|
|
64
|
+
readonly rules?: readonly SEORule[];
|
|
37
65
|
}
|
|
38
66
|
/** hreflang → absolute or path URL (adapter maps to framework expectations). */
|
|
39
67
|
interface SEOAlternates {
|
|
@@ -45,6 +73,8 @@ interface SEOMeta {
|
|
|
45
73
|
readonly canonical?: string;
|
|
46
74
|
readonly robots?: string;
|
|
47
75
|
readonly alternates?: SEOAlternates;
|
|
76
|
+
readonly verification?: SEOVerification;
|
|
77
|
+
readonly pagination?: SEOPagination;
|
|
48
78
|
}
|
|
49
79
|
interface SEOImage {
|
|
50
80
|
readonly url: string;
|
|
@@ -52,6 +82,14 @@ interface SEOImage {
|
|
|
52
82
|
readonly height?: number;
|
|
53
83
|
readonly alt?: string;
|
|
54
84
|
}
|
|
85
|
+
/** Open Graph `og:video` group — used when `openGraph.type` is `video.*` or for rich previews. */
|
|
86
|
+
interface SEOOpenGraphVideo {
|
|
87
|
+
readonly url: string;
|
|
88
|
+
readonly secureUrl?: string;
|
|
89
|
+
readonly type?: string;
|
|
90
|
+
readonly width?: number;
|
|
91
|
+
readonly height?: number;
|
|
92
|
+
}
|
|
55
93
|
interface SEO {
|
|
56
94
|
readonly meta: SEOMeta;
|
|
57
95
|
readonly openGraph?: {
|
|
@@ -59,10 +97,31 @@ interface SEO {
|
|
|
59
97
|
readonly description?: string;
|
|
60
98
|
readonly url?: string;
|
|
61
99
|
readonly type?: string;
|
|
100
|
+
/** `og:site_name` — brand shown in Facebook / LinkedIn / Slack previews. */
|
|
101
|
+
readonly siteName?: string;
|
|
102
|
+
/** `og:locale` — e.g. `en_US`. */
|
|
103
|
+
readonly locale?: string;
|
|
104
|
+
/** `article:published_time` (ISO-8601). */
|
|
105
|
+
readonly publishedTime?: string;
|
|
106
|
+
/** `article:modified_time` */
|
|
107
|
+
readonly modifiedTime?: string;
|
|
108
|
+
/** `article:expiration_time` */
|
|
109
|
+
readonly expirationTime?: string;
|
|
110
|
+
/** `article:author` (repeat per entry). */
|
|
111
|
+
readonly authors?: readonly string[];
|
|
112
|
+
/** `article:section` */
|
|
113
|
+
readonly section?: string;
|
|
114
|
+
/** `article:tag` (repeat per entry). */
|
|
115
|
+
readonly tags?: readonly string[];
|
|
62
116
|
readonly images?: readonly SEOImage[];
|
|
117
|
+
readonly videos?: readonly SEOOpenGraphVideo[];
|
|
63
118
|
};
|
|
64
119
|
readonly twitter?: {
|
|
65
120
|
readonly card?: "summary" | "summary_large_image";
|
|
121
|
+
/** `twitter:site` — @handle or numeric string per Twitter Card spec. */
|
|
122
|
+
readonly site?: string;
|
|
123
|
+
/** `twitter:creator` */
|
|
124
|
+
readonly creator?: string;
|
|
66
125
|
readonly title?: string;
|
|
67
126
|
readonly description?: string;
|
|
68
127
|
readonly image?: string;
|
|
@@ -106,7 +165,7 @@ type TagDescriptor = {
|
|
|
106
165
|
};
|
|
107
166
|
|
|
108
167
|
/** Stable codes for programmatic handling (enterprise / observability). */
|
|
109
|
-
type SEOErrorCode = "VALIDATION" | "ADAPTER_NOT_FOUND" | "
|
|
168
|
+
type SEOErrorCode = "VALIDATION" | "ADAPTER_NOT_FOUND" | "USE_SEO_NOT_AVAILABLE" | "USE_SEO_NO_PROVIDER";
|
|
110
169
|
declare class SEOError extends Error {
|
|
111
170
|
readonly code: SEOErrorCode;
|
|
112
171
|
readonly cause?: unknown;
|
|
@@ -187,11 +246,11 @@ declare function customSchema(node: JSONLD): JSONLD;
|
|
|
187
246
|
declare function serializeJSONLD(data: JSONLD | readonly JSONLD[]): string;
|
|
188
247
|
|
|
189
248
|
/** Vanilla tag list for snapshots and non-framework hosts (ARCHITECTURE §8). */
|
|
190
|
-
declare function renderTags(seo: SEO): TagDescriptor[];
|
|
249
|
+
declare function renderTags(seo: SEO, config?: SEOConfig): TagDescriptor[];
|
|
191
250
|
|
|
192
251
|
type ValidationSeverity = "warning" | "error";
|
|
193
252
|
/** Stable machine-readable codes (PRD §3.5 / observability). */
|
|
194
|
-
type ValidationIssueCode = "TITLE_EMPTY" | "TITLE_TOO_LONG" | "DESCRIPTION_MISSING" | "DESCRIPTION_REQUIRED" | "DESCRIPTION_TOO_LONG" | "OG_IMAGE_NARROW" | "SCHEMA_MISSING_TYPE";
|
|
253
|
+
type ValidationIssueCode = "TITLE_EMPTY" | "TITLE_TOO_LONG" | "DESCRIPTION_MISSING" | "DESCRIPTION_REQUIRED" | "DESCRIPTION_TOO_LONG" | "OG_IMAGE_NARROW" | "ARTICLE_PUBLISHED_TIME_RECOMMENDED" | "SCHEMA_MISSING_TYPE";
|
|
195
254
|
interface ValidationIssue {
|
|
196
255
|
readonly code: ValidationIssueCode;
|
|
197
256
|
readonly field: string;
|
|
@@ -236,6 +295,11 @@ declare function validateSEO(seo: SEO, options?: ValidateSEOOptions): readonly V
|
|
|
236
295
|
declare function registerAdapter<T>(adapter: SEOAdapter<T>): void;
|
|
237
296
|
declare function getAdapter<T = unknown>(id: string): SEOAdapter<T> | undefined;
|
|
238
297
|
declare function listAdapterIds(): string[];
|
|
298
|
+
/**
|
|
299
|
+
* Best-effort only (e.g. `NEXT_RUNTIME` under Next). Prefer explicit `registerAdapter` / `@better-seo/<framework>` imports in production.
|
|
300
|
+
*/
|
|
301
|
+
declare function detectFramework(): "next" | undefined;
|
|
302
|
+
declare function getDefaultAdapter<T = unknown>(): SEOAdapter<T> | undefined;
|
|
239
303
|
|
|
240
304
|
declare function defineSEOPlugin(plugin: SEOPlugin): SEOPlugin;
|
|
241
305
|
|
|
@@ -243,6 +307,8 @@ interface SEOContext {
|
|
|
243
307
|
readonly config: SEOConfig;
|
|
244
308
|
/** Request-scoped `createSEO` with bound config + plugins. */
|
|
245
309
|
readonly createSEO: (input: SEOInput) => SEO;
|
|
310
|
+
/** Merges `config.rules` for `route`, then `createSEO` (N9 / Wave 6). */
|
|
311
|
+
readonly createSEOForRoute: (route: string, input: SEOInput) => SEO;
|
|
246
312
|
readonly mergeSEO: (parent: SEO, child: SEOInput) => SEO;
|
|
247
313
|
}
|
|
248
314
|
/**
|
|
@@ -303,6 +369,11 @@ declare function seoForFramework<T>(adapterId: string, input: SEOInput, config?:
|
|
|
303
369
|
* @throws {SEOError} USE_SEO_NOT_AVAILABLE
|
|
304
370
|
*/
|
|
305
371
|
declare function useSEO(): never;
|
|
372
|
+
/**
|
|
373
|
+
* V5 — explicit pathname for rules: merges {@link SEOConfig.rules} (via `applyRules`) then {@link createSEO}.
|
|
374
|
+
* Prefer this over “magic” route detection at runtime (FEATURES **V6** — document limits; no stable `seo.auto` in core).
|
|
375
|
+
*/
|
|
376
|
+
declare function seoRoute(route: string, input: SEOInput, config?: SEOConfig): SEO;
|
|
306
377
|
|
|
307
378
|
/**
|
|
308
379
|
* Pure rule matcher — `**` segment globs + legacy `prefix*` path match (ARCHITECTURE §11 subset).
|
|
@@ -314,9 +385,37 @@ declare function applyRulesToSEO(route: string, base: SEO, rules: readonly SEORu
|
|
|
314
385
|
declare function createSEOForRoute(route: string, input: SEOInput, rules: readonly SEORule[], config?: SEOConfig): SEO;
|
|
315
386
|
|
|
316
387
|
/**
|
|
317
|
-
*
|
|
318
|
-
*
|
|
388
|
+
* Map next-seo **`DefaultSeo`** / **`NextSeo`**-style props → {@link SEOInput}.
|
|
389
|
+
* Covers common `title`, `description`, `canonical`, `openGraph`, `twitter`, `noindex`, `nofollow`.
|
|
390
|
+
* Use `createSEO(fromNextSeo(props), config)` — `titleTemplate` from next-seo is not applied; set `SEOConfig.titleTemplate` yourself.
|
|
391
|
+
*/
|
|
392
|
+
declare function fromNextSeo(nextSeoExport: unknown): SEOInput;
|
|
393
|
+
|
|
394
|
+
interface FromContentOptions {
|
|
395
|
+
/** Truncate generated description (default 300). */
|
|
396
|
+
readonly maxDescriptionLength?: number;
|
|
397
|
+
/**
|
|
398
|
+
* When **`false`**, do not derive **title** from `# heading` or the first body line (description-only inference).
|
|
399
|
+
* Use when the caller already has a title (e.g. **gray-matter** frontmatter via **`@better-seo/compiler`**).
|
|
400
|
+
* @default true
|
|
401
|
+
*/
|
|
402
|
+
readonly inferTitleFromBody?: boolean;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Wave 7 / **C16** — derive {@link SEOInput} from a string (plain text, Markdown, or MDX-ish).
|
|
406
|
+
* Does **not** compile MDX: treats `import` / JSX as text; use for metadata hints only.
|
|
407
|
+
* Optional YAML frontmatter (`---` … `---`) with `title` / `description` is supported.
|
|
408
|
+
*/
|
|
409
|
+
declare function fromContent(markdownOrPlain: string, options?: FromContentOptions): SEOInput;
|
|
410
|
+
/**
|
|
411
|
+
* Wave 7 — convenience alias of {@link fromContent} (same zero-dep behavior).
|
|
412
|
+
* For **gray-matter** frontmatter + body merging, use **`fromMdx`** from **`@better-seo/compiler`** (**C17**).
|
|
413
|
+
*/
|
|
414
|
+
declare function fromMdxString(source: string, options?: FromContentOptions): SEOInput;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* **C18** — Preserves a typed {@link SEOInput} literal for templates / config snippets (no runtime transform).
|
|
319
418
|
*/
|
|
320
|
-
declare function
|
|
419
|
+
declare function defineSEO<const T extends SEOInput>(input: T): T;
|
|
321
420
|
|
|
322
|
-
export { type JSONLD, type JSONLDValue, type SEO, type SEOAdapter, type SEOAlternates, type SEOConfig, type SEOContext, SEOError, type SEOErrorCode, type SEOImage, type SEOInput, type SEOMeta, type SEOPlugin, type SEORule, type TagDescriptor, type ValidateSEOOptions, type ValidationIssue, type ValidationIssueCode, type ValidationSeverity, applyRules, applyRulesToSEO, article, breadcrumbList, createSEO, createSEOContext, createSEOForRoute, customSchema, defineSEOPlugin, faqPage, fromNextSeo, getAdapter, getGlobalSEOConfig, initSEO, isSEOError, listAdapterIds, mergeSEO, organization, person, product, registerAdapter, renderTags, resetSEOConfigForTests, seoForFramework, serializeJSONLD, techArticle, useSEO, validateSEO, webPage, withSEO };
|
|
421
|
+
export { type FromContentOptions, type JSONLD, type JSONLDValue, type SEO, type SEOAdapter, type SEOAlternates, type SEOConfig, type SEOContext, SEOError, type SEOErrorCode, type SEOImage, type SEOInput, type SEOMeta, type SEOOpenGraphVideo, type SEOPagination, type SEOPlugin, type SEORule, type SEOVerification, type TagDescriptor, type ValidateSEOOptions, type ValidationIssue, type ValidationIssueCode, type ValidationSeverity, applyRules, applyRulesToSEO, article, breadcrumbList, createSEO, createSEOContext, createSEOForRoute, customSchema, defineSEO, defineSEOPlugin, detectFramework, faqPage, fromContent, fromMdxString, fromNextSeo, getAdapter, getDefaultAdapter, getGlobalSEOConfig, initSEO, isSEOError, listAdapterIds, mergeSEO, organization, person, product, registerAdapter, renderTags, resetSEOConfigForTests, seoForFramework, seoRoute, serializeJSONLD, techArticle, useSEO, validateSEO, webPage, withSEO };
|