@coherent.js/seo 1.0.0-beta.5 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/types/index.d.ts +337 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/seo",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "SEO utilities for Coherent.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "author": "Coherent.js Team",
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "@coherent.js/core": "1.0.0-beta.5"
23
+ "@coherent.js/core": "1.0.0-beta.6"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
package/types/index.d.ts CHANGED
@@ -3,8 +3,164 @@
3
3
  * @module @coherent.js/seo
4
4
  */
5
5
 
6
- // ===== Meta Builder Types =====
6
+ import type { CoherentNode } from '@coherent.js/core';
7
7
 
8
+ // ============================================================================
9
+ // Meta Tag Types
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Generic meta tag definition
14
+ */
15
+ export interface MetaTag {
16
+ /** Meta name attribute (for standard meta tags) */
17
+ name?: string;
18
+ /** Meta property attribute (for Open Graph, etc.) */
19
+ property?: string;
20
+ /** Meta content value */
21
+ content: string;
22
+ /** HTTP-equiv attribute */
23
+ httpEquiv?: string;
24
+ }
25
+
26
+ /**
27
+ * Open Graph image configuration
28
+ */
29
+ export interface OpenGraphImage {
30
+ /** Image URL */
31
+ url: string;
32
+ /** Image width in pixels */
33
+ width?: number;
34
+ /** Image height in pixels */
35
+ height?: number;
36
+ /** Image alt text */
37
+ alt?: string;
38
+ /** Image MIME type */
39
+ type?: string;
40
+ }
41
+
42
+ /**
43
+ * Open Graph meta configuration
44
+ */
45
+ export interface OpenGraphMeta {
46
+ /** Page title */
47
+ title: string;
48
+ /** Page description */
49
+ description?: string;
50
+ /** Content type */
51
+ type?: 'website' | 'article' | 'book' | 'profile' | 'video.movie' | 'video.episode' | 'music.song' | 'music.album';
52
+ /** Page URL */
53
+ url?: string;
54
+ /** Image(s) for sharing */
55
+ image?: string | OpenGraphImage | (string | OpenGraphImage)[];
56
+ /** Site name */
57
+ siteName?: string;
58
+ /** Locale (e.g., 'en_US') */
59
+ locale?: string;
60
+ /** Alternate locales */
61
+ alternateLocales?: string[];
62
+ /** Audio URL */
63
+ audio?: string;
64
+ /** Video URL */
65
+ video?: string;
66
+ /** Determiner (a, an, the, auto, or empty) */
67
+ determiner?: 'a' | 'an' | 'the' | 'auto' | '';
68
+ }
69
+
70
+ /**
71
+ * Twitter Card meta configuration
72
+ */
73
+ export interface TwitterMeta {
74
+ /** Card type */
75
+ card?: 'summary' | 'summary_large_image' | 'app' | 'player';
76
+ /** Twitter @username of website */
77
+ site?: string;
78
+ /** Twitter @username of content creator */
79
+ creator?: string;
80
+ /** Card title (defaults to og:title) */
81
+ title?: string;
82
+ /** Card description (defaults to og:description) */
83
+ description?: string;
84
+ /** Card image (defaults to og:image) */
85
+ image?: string;
86
+ /** Image alt text */
87
+ imageAlt?: string;
88
+ /** App ID for app cards */
89
+ appIdIphone?: string;
90
+ /** App ID for iPad */
91
+ appIdIpad?: string;
92
+ /** App ID for Google Play */
93
+ appIdGooglePlay?: string;
94
+ }
95
+
96
+ /**
97
+ * Comprehensive SEO configuration
98
+ */
99
+ export interface SEOConfig {
100
+ /** Page title */
101
+ title: string;
102
+ /** Title template (e.g., '%s | My Site') */
103
+ titleTemplate?: string;
104
+ /** Page description */
105
+ description?: string;
106
+ /** Canonical URL */
107
+ canonical?: string;
108
+ /** Robots directives (e.g., 'index, follow') */
109
+ robots?: string;
110
+ /** Additional meta tags */
111
+ meta?: MetaTag[];
112
+ /** Open Graph configuration */
113
+ openGraph?: OpenGraphMeta;
114
+ /** Twitter Card configuration */
115
+ twitter?: TwitterMeta;
116
+ /** JSON-LD structured data */
117
+ jsonLd?: Record<string, unknown> | Record<string, unknown>[];
118
+ /** Keywords (comma-separated or array) */
119
+ keywords?: string | string[];
120
+ /** Author name */
121
+ author?: string;
122
+ /** Viewport settings */
123
+ viewport?: string;
124
+ /** Character set */
125
+ charset?: string;
126
+ /** Language code */
127
+ language?: string;
128
+ /** Theme color */
129
+ themeColor?: string;
130
+ }
131
+
132
+ // ============================================================================
133
+ // SEO Generation Functions
134
+ // ============================================================================
135
+
136
+ /**
137
+ * Generate meta tags from SEO configuration
138
+ * @returns Array of meta element nodes
139
+ */
140
+ export function generateMeta(config: SEOConfig): CoherentNode[];
141
+
142
+ /**
143
+ * Generate JSON-LD script tag from data
144
+ */
145
+ export function generateJsonLd(data: Record<string, unknown>): CoherentNode;
146
+
147
+ /**
148
+ * Create a reusable SEO component from configuration
149
+ */
150
+ export function createSEOComponent(config: SEOConfig): () => CoherentNode;
151
+
152
+ /**
153
+ * Merge multiple SEO configurations (later configs override earlier)
154
+ */
155
+ export function mergeSEOConfig(...configs: Partial<SEOConfig>[]): SEOConfig;
156
+
157
+ // ============================================================================
158
+ // Meta Builder
159
+ // ============================================================================
160
+
161
+ /**
162
+ * All meta tags in a flat structure
163
+ */
8
164
  export interface MetaTags {
9
165
  title?: string;
10
166
  description?: string;
@@ -32,41 +188,88 @@ export interface MetaTags {
32
188
  twitterDescription?: string;
33
189
  twitterImage?: string;
34
190
  // Custom meta tags
35
- [key: string]: any;
191
+ [key: string]: unknown;
36
192
  }
37
193
 
194
+ /**
195
+ * Fluent builder for meta tags
196
+ */
38
197
  export class MetaBuilder {
39
198
  constructor(tags?: MetaTags);
199
+
200
+ /** Set page title */
40
201
  setTitle(title: string): this;
202
+
203
+ /** Set page description */
41
204
  setDescription(description: string): this;
205
+
206
+ /** Set keywords */
42
207
  setKeywords(keywords: string | string[]): this;
208
+
209
+ /** Set author */
43
210
  setAuthor(author: string): this;
211
+
212
+ /** Set robots directive */
44
213
  setRobots(robots: string): this;
214
+
215
+ /** Set canonical URL */
45
216
  setCanonical(url: string): this;
217
+
218
+ /** Set viewport */
46
219
  setViewport(viewport: string): this;
47
- setOpenGraph(tags: Partial<MetaTags>): this;
48
- setTwitterCard(tags: Partial<MetaTags>): this;
220
+
221
+ /** Set Open Graph properties */
222
+ setOpenGraph(tags: Partial<OpenGraphMeta>): this;
223
+
224
+ /** Set Twitter Card properties */
225
+ setTwitterCard(tags: Partial<TwitterMeta>): this;
226
+
227
+ /** Add a custom meta tag */
49
228
  addCustomTag(name: string, content: string, type?: 'name' | 'property'): this;
50
- build(): object;
51
- render(): object;
229
+
230
+ /** Build as CoherentNode */
231
+ build(): CoherentNode;
232
+
233
+ /** Alias for build */
234
+ render(): CoherentNode;
235
+
236
+ /** Convert to HTML string */
52
237
  toHTML(): string;
53
238
  }
54
239
 
240
+ /**
241
+ * Create a MetaBuilder instance
242
+ */
55
243
  export function createMetaBuilder(tags?: MetaTags): MetaBuilder;
56
- export function generateMeta(tags: MetaTags): object;
57
244
 
58
- // ===== Sitemap Generator Types =====
245
+ /**
246
+ * Generate meta nodes from flat tags
247
+ */
248
+ export function generateMeta(tags: MetaTags): CoherentNode;
59
249
 
250
+ // ============================================================================
251
+ // Sitemap Generator
252
+ // ============================================================================
253
+
254
+ /**
255
+ * Sitemap entry configuration
256
+ */
60
257
  export interface SitemapEntry {
258
+ /** Page URL */
61
259
  url: string;
260
+ /** Last modification date */
62
261
  lastmod?: string | Date;
262
+ /** Change frequency */
63
263
  changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
264
+ /** Priority (0.0 to 1.0) */
64
265
  priority?: number;
266
+ /** Image entries */
65
267
  images?: Array<{
66
268
  loc: string;
67
269
  title?: string;
68
270
  caption?: string;
69
271
  }>;
272
+ /** Video entries */
70
273
  videos?: Array<{
71
274
  thumbnail_loc: string;
72
275
  title: string;
@@ -74,30 +277,69 @@ export interface SitemapEntry {
74
277
  content_loc?: string;
75
278
  player_loc?: string;
76
279
  }>;
280
+ /** Alternate language versions */
281
+ alternates?: Array<{
282
+ hreflang: string;
283
+ href: string;
284
+ }>;
77
285
  }
78
286
 
287
+ /**
288
+ * Sitemap generator options
289
+ */
79
290
  export interface SitemapOptions {
291
+ /** Site hostname (e.g., 'https://example.com') */
80
292
  hostname: string;
293
+ /** Cache time in milliseconds */
81
294
  cacheTime?: number;
295
+ /** XML namespaces */
82
296
  xmlNs?: Record<string, string>;
297
+ /** XSL stylesheet URL */
83
298
  xslUrl?: string;
84
299
  }
85
300
 
301
+ /**
302
+ * Sitemap generator class
303
+ */
86
304
  export class SitemapGenerator {
87
305
  constructor(options: SitemapOptions);
306
+
307
+ /** Add a URL entry */
88
308
  addUrl(entry: SitemapEntry): this;
309
+
310
+ /** Add multiple URL entries */
89
311
  addUrls(entries: SitemapEntry[]): this;
312
+
313
+ /** Remove a URL entry */
90
314
  removeUrl(url: string): this;
315
+
316
+ /** Generate sitemap XML string */
91
317
  generate(): string;
318
+
319
+ /** Alias for generate */
92
320
  toXML(): string;
321
+
322
+ /** Export entries as JSON */
93
323
  toJSON(): SitemapEntry[];
94
324
  }
95
325
 
326
+ /**
327
+ * Create a sitemap generator
328
+ */
96
329
  export function createSitemapGenerator(options: SitemapOptions): SitemapGenerator;
330
+
331
+ /**
332
+ * Generate sitemap XML from entries
333
+ */
97
334
  export function generateSitemap(entries: SitemapEntry[], options: SitemapOptions): string;
98
335
 
99
- // ===== Structured Data Types =====
336
+ // ============================================================================
337
+ // Structured Data (JSON-LD)
338
+ // ============================================================================
100
339
 
340
+ /**
341
+ * Supported structured data types
342
+ */
101
343
  export type StructuredDataType =
102
344
  | 'Article'
103
345
  | 'BlogPosting'
@@ -115,30 +357,71 @@ export type StructuredDataType =
115
357
  | 'FAQPage'
116
358
  | 'HowTo'
117
359
  | 'VideoObject'
118
- | 'ImageObject';
360
+ | 'ImageObject'
361
+ | 'SoftwareApplication'
362
+ | 'Course'
363
+ | 'JobPosting';
119
364
 
365
+ /**
366
+ * Structured data object
367
+ */
120
368
  export interface StructuredData {
121
369
  '@context': string;
122
370
  '@type': StructuredDataType | StructuredDataType[];
123
- [key: string]: any;
371
+ [key: string]: unknown;
124
372
  }
125
373
 
374
+ /**
375
+ * Fluent builder for structured data
376
+ */
126
377
  export class StructuredDataBuilder {
127
378
  constructor(type: StructuredDataType);
379
+
380
+ /** Change the schema type */
128
381
  setType(type: StructuredDataType): this;
129
- setProperty(key: string, value: any): this;
130
- setProperties(properties: Record<string, any>): this;
131
- addToArray(key: string, value: any): this;
382
+
383
+ /** Set a single property */
384
+ setProperty(key: string, value: unknown): this;
385
+
386
+ /** Set multiple properties */
387
+ setProperties(properties: Record<string, unknown>): this;
388
+
389
+ /** Add value to an array property */
390
+ addToArray(key: string, value: unknown): this;
391
+
392
+ /** Build the structured data object */
132
393
  build(): StructuredData;
394
+
395
+ /** Convert to JSON string */
133
396
  toJSON(): string;
134
- toJSONLD(): object;
397
+
398
+ /** Build as JSON-LD script node */
399
+ toJSONLD(): CoherentNode;
135
400
  }
136
401
 
137
- export function createStructuredData(type: StructuredDataType, properties?: Record<string, any>): StructuredDataBuilder;
138
- export function generateStructuredData(type: StructuredDataType, properties: Record<string, any>): StructuredData;
402
+ /**
403
+ * Create a structured data builder
404
+ */
405
+ export function createStructuredData(
406
+ type: StructuredDataType,
407
+ properties?: Record<string, unknown>
408
+ ): StructuredDataBuilder;
409
+
410
+ /**
411
+ * Generate structured data object
412
+ */
413
+ export function generateStructuredData(
414
+ type: StructuredDataType,
415
+ properties: Record<string, unknown>
416
+ ): StructuredData;
139
417
 
140
- // Helper types for common structured data
418
+ // ============================================================================
419
+ // Common Structured Data Types
420
+ // ============================================================================
141
421
 
422
+ /**
423
+ * Article structured data
424
+ */
142
425
  export interface ArticleData {
143
426
  headline: string;
144
427
  image: string | string[];
@@ -160,6 +443,9 @@ export interface ArticleData {
160
443
  mainEntityOfPage?: string;
161
444
  }
162
445
 
446
+ /**
447
+ * Product structured data
448
+ */
163
449
  export interface ProductData {
164
450
  name: string;
165
451
  image: string | string[];
@@ -182,6 +468,9 @@ export interface ProductData {
182
468
  };
183
469
  }
184
470
 
471
+ /**
472
+ * Breadcrumb structured data
473
+ */
185
474
  export interface BreadcrumbData {
186
475
  itemListElement: Array<{
187
476
  '@type': 'ListItem';
@@ -190,3 +479,33 @@ export interface BreadcrumbData {
190
479
  item?: string;
191
480
  }>;
192
481
  }
482
+
483
+ /**
484
+ * Organization structured data
485
+ */
486
+ export interface OrganizationData {
487
+ name: string;
488
+ url?: string;
489
+ logo?: string;
490
+ description?: string;
491
+ sameAs?: string[];
492
+ contactPoint?: {
493
+ '@type': 'ContactPoint';
494
+ telephone: string;
495
+ contactType: string;
496
+ };
497
+ }
498
+
499
+ /**
500
+ * FAQ Page structured data
501
+ */
502
+ export interface FAQPageData {
503
+ mainEntity: Array<{
504
+ '@type': 'Question';
505
+ name: string;
506
+ acceptedAnswer: {
507
+ '@type': 'Answer';
508
+ text: string;
509
+ };
510
+ }>;
511
+ }