@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/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" | "MIGRATE_NOT_IMPLEMENTED" | "USE_SEO_NOT_AVAILABLE";
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
- * Codemod-oriented helpers stub until Wave 12 / CLI `migrate` (FEATURES C15).
318
- * @throws {SEOError} MIGRATE_NOT_IMPLEMENTED
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 fromNextSeo(_nextSeoExport: unknown): never;
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 };