@coherent.js/seo 1.0.0-beta.3 → 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 (3) hide show
  1. package/README.md +681 -0
  2. package/package.json +3 -2
  3. package/types/index.d.ts +337 -18
package/README.md ADDED
@@ -0,0 +1,681 @@
1
+ # @coherent.js/seo
2
+
3
+ SEO optimization tools for Coherent.js applications - Meta tags, structured data, and search engine optimization utilities.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @coherent.js/seo
9
+ # or
10
+ pnpm add @coherent.js/seo
11
+ # or
12
+ yarn add @coherent.js/seo
13
+ ```
14
+
15
+ ## Overview
16
+
17
+ The `@coherent.js/seo` package provides comprehensive SEO tools for Coherent.js applications, including:
18
+
19
+ - Dynamic meta tag management
20
+ - Open Graph and Twitter Card support
21
+ - JSON-LD structured data generation
22
+ - Sitemap generation
23
+ - Robots.txt management
24
+ - SEO-friendly URL generation
25
+ - Canonical URL support
26
+ - Internationalization SEO
27
+
28
+ ## Quick Start
29
+
30
+ ```javascript
31
+ import { createSEOHooks } from '@coherent.js/seo';
32
+
33
+ // Create SEO hooks
34
+ const seo = createSEOHooks();
35
+
36
+ // Add to your Coherent.js component
37
+ function BlogPost({ post }) {
38
+ // Set SEO metadata
39
+ seo.setMetadata({
40
+ title: `${post.title} - My Blog`,
41
+ description: post.excerpt,
42
+ keywords: post.tags,
43
+ author: post.author.name,
44
+ publishedTime: post.publishedAt,
45
+ image: post.featuredImage
46
+ });
47
+
48
+ return {
49
+ div: {
50
+ children: [
51
+ { h1: { text: post.title } },
52
+ { div: {
53
+ innerHTML: post.content,
54
+ className: 'post-content'
55
+ }}
56
+ ]
57
+ }
58
+ };
59
+ }
60
+ ```
61
+
62
+ ## Features
63
+
64
+ ### Dynamic Meta Tags
65
+
66
+ Automatically generate meta tags for search engines:
67
+
68
+ ```javascript
69
+ import { createSEOHooks } from '@coherent.js/seo';
70
+
71
+ const seo = createSEOHooks();
72
+
73
+ function ProductPage({ product }) {
74
+ seo.setMetadata({
75
+ title: product.name,
76
+ description: product.description,
77
+ keywords: [product.category, product.brand, ...product.tags],
78
+ image: product.images[0],
79
+ locale: 'en_US',
80
+ type: 'product',
81
+ url: `https://example.com/products/${product.slug}`
82
+ });
83
+
84
+ return {
85
+ div: {
86
+ children: [
87
+ { h1: { text: product.name } },
88
+ { p: { text: product.description } },
89
+ { img: { src: product.images[0], alt: product.name } }
90
+ ]
91
+ }
92
+ };
93
+ }
94
+ ```
95
+
96
+ ### Open Graph Support
97
+
98
+ Generate Open Graph meta tags for social sharing:
99
+
100
+ ```javascript
101
+ seo.setMetadata({
102
+ title: 'Awesome Product',
103
+ description: 'This product will change your life',
104
+ image: 'https://example.com/product-image.jpg',
105
+ type: 'product.item',
106
+ siteName: 'My E-commerce Store',
107
+ locale: 'en_US',
108
+
109
+ // Open Graph specific
110
+ og: {
111
+ price: {
112
+ amount: '29.99',
113
+ currency: 'USD'
114
+ },
115
+ availability: 'instock'
116
+ }
117
+ });
118
+ ```
119
+
120
+ ### Twitter Card Support
121
+
122
+ Generate Twitter Card meta tags:
123
+
124
+ ```javascript
125
+ seo.setMetadata({
126
+ title: 'Check out this awesome content!',
127
+ description: 'You won\'t believe what happens next',
128
+ image: 'https://example.com/twitter-card-image.jpg',
129
+
130
+ // Twitter specific
131
+ twitter: {
132
+ card: 'summary_large_image',
133
+ site: '@mywebsite',
134
+ creator: '@author'
135
+ }
136
+ });
137
+ ```
138
+
139
+ ### JSON-LD Structured Data
140
+
141
+ Generate structured data for rich search results:
142
+
143
+ ```javascript
144
+ import { createArticleSchema, createBreadcrumbSchema } from '@coherent.js/seo';
145
+
146
+ function BlogPost({ post, breadcrumbs }) {
147
+ // Add article structured data
148
+ seo.addSchema(createArticleSchema({
149
+ headline: post.title,
150
+ description: post.excerpt,
151
+ author: {
152
+ name: post.author.name,
153
+ url: `/authors/${post.author.slug}`
154
+ },
155
+ datePublished: post.publishedAt,
156
+ dateModified: post.updatedAt,
157
+ image: post.featuredImage,
158
+ keywords: post.tags,
159
+ articleBody: post.content
160
+ }));
161
+
162
+ // Add breadcrumb schema
163
+ seo.addSchema(createBreadcrumbSchema(breadcrumbs));
164
+
165
+ return {
166
+ div: {
167
+ children: [
168
+ { h1: { text: post.title } },
169
+ { div: { innerHTML: post.content } }
170
+ ]
171
+ }
172
+ };
173
+ }
174
+ ```
175
+
176
+ ## SEO Hooks
177
+
178
+ ### Basic Usage
179
+
180
+ ```javascript
181
+ import { createSEOHooks } from '@coherent.js/seo';
182
+
183
+ const seo = createSEOHooks({
184
+ defaultTitle: 'My Website',
185
+ defaultDescription: 'Welcome to my awesome website',
186
+ defaultImage: '/default-social-image.jpg',
187
+ siteUrl: 'https://example.com'
188
+ });
189
+
190
+ function Page({ title, description }) {
191
+ seo.setMetadata({
192
+ title: title,
193
+ description: description
194
+ });
195
+
196
+ return {
197
+ div: {
198
+ children: [
199
+ { h1: { text: title } },
200
+ { p: { text: description } }
201
+ ]
202
+ }
203
+ };
204
+ }
205
+ ```
206
+
207
+ ### Advanced Configuration
208
+
209
+ ```javascript
210
+ const seo = createSEOHooks({
211
+ // Default metadata
212
+ defaultTitle: 'My Website',
213
+ defaultDescription: 'Default description',
214
+ defaultImage: '/images/default.jpg',
215
+ siteUrl: 'https://example.com',
216
+
217
+ // SEO settings
218
+ titleTemplate: '%s | My Website', // "Page Title | My Website"
219
+ truncateTitle: 60, // Truncate titles to 60 chars
220
+ truncateDescription: 160, // Truncate descriptions to 160 chars
221
+
222
+ // Social media
223
+ social: {
224
+ twitter: '@mytwitterhandle',
225
+ facebook: 'myfacebookpage',
226
+ linkedin: 'mylinkedincompany'
227
+ },
228
+
229
+ // Default Open Graph
230
+ og: {
231
+ type: 'website',
232
+ siteName: 'My Website'
233
+ }
234
+ });
235
+ ```
236
+
237
+ ## Sitemap Generation
238
+
239
+ Generate dynamic sitemaps:
240
+
241
+ ```javascript
242
+ import { createSitemap } from '@coherent.js/seo';
243
+
244
+ const sitemap = createSitemap({
245
+ siteUrl: 'https://example.com',
246
+ changefreq: 'daily',
247
+ priority: 0.7,
248
+ lastmod: new Date()
249
+ });
250
+
251
+ // Add URLs to sitemap
252
+ sitemap.add({
253
+ url: '/',
254
+ changefreq: 'daily',
255
+ priority: 1.0
256
+ });
257
+
258
+ sitemap.add({
259
+ url: '/about',
260
+ changefreq: 'monthly',
261
+ priority: 0.8
262
+ });
263
+
264
+ sitemap.add({
265
+ url: '/blog',
266
+ changefreq: 'weekly',
267
+ priority: 0.9
268
+ });
269
+
270
+ // Generate sitemap XML
271
+ const sitemapXml = sitemap.toXML();
272
+ ```
273
+
274
+ ## Robots.txt Management
275
+
276
+ Generate robots.txt files:
277
+
278
+ ```javascript
279
+ import { createRobotsTxt } from '@coherent.js/seo';
280
+
281
+ const robots = createRobotsTxt({
282
+ userAgent: '*', // Default user agent
283
+ allow: ['/'], // Allow all paths
284
+ disallow: ['/admin', '/private'], // Disallow specific paths
285
+ sitemap: 'https://example.com/sitemap.xml',
286
+ host: 'https://example.com'
287
+ });
288
+
289
+ // Add custom rules
290
+ robots.addRule({
291
+ userAgent: 'Googlebot',
292
+ allow: ['/'],
293
+ crawlDelay: 10
294
+ });
295
+
296
+ // Generate robots.txt content
297
+ const robotsTxt = robots.toString();
298
+ ```
299
+
300
+ ## Canonical URLs
301
+
302
+ Manage canonical URLs to prevent duplicate content issues:
303
+
304
+ ```javascript
305
+ function ProductPage({ product, queryParams }) {
306
+ // Set canonical URL without tracking parameters
307
+ const canonicalUrl = `https://example.com/products/${product.slug}`;
308
+
309
+ seo.setCanonical(canonicalUrl);
310
+
311
+ // Add alternate URLs for internationalization
312
+ seo.addAlternate({
313
+ href: `https://example.com/en/products/${product.slug}`,
314
+ hreflang: 'en'
315
+ });
316
+
317
+ seo.addAlternate({
318
+ href: `https://example.com/es/products/${product.slug}`,
319
+ hreflang: 'es'
320
+ });
321
+
322
+ return {
323
+ div: {
324
+ children: [
325
+ { h1: { text: product.name } },
326
+ { p: { text: product.description } }
327
+ ]
328
+ }
329
+ };
330
+ }
331
+ ```
332
+
333
+ ## Internationalization SEO
334
+
335
+ Support for multilingual SEO:
336
+
337
+ ```javascript
338
+ function MultilingualPage({ content, language, translations }) {
339
+ // Set language
340
+ seo.setLanguage(language);
341
+
342
+ // Add alternate language versions
343
+ Object.entries(translations).forEach(([lang, url]) => {
344
+ seo.addAlternate({
345
+ href: url,
346
+ hreflang: lang
347
+ });
348
+ });
349
+
350
+ // Set direction for RTL languages
351
+ seo.setDirection(language === 'ar' || language === 'he' ? 'rtl' : 'ltr');
352
+
353
+ return {
354
+ div: {
355
+ lang: language,
356
+ children: [
357
+ { h1: { text: content.title } },
358
+ { div: { innerHTML: content.body } }
359
+ ]
360
+ }
361
+ };
362
+ }
363
+ ```
364
+
365
+ ## API Reference
366
+
367
+ ### createSEOHooks(options)
368
+
369
+ Create SEO hooks for metadata management.
370
+
371
+ **Parameters:**
372
+ - `options.defaultTitle` - Default page title
373
+ - `options.defaultDescription` - Default page description
374
+ - `options.defaultImage` - Default social image
375
+ - `options.siteUrl` - Base site URL
376
+ - `options.titleTemplate` - Title template string
377
+ - `options.truncateTitle` - Title character limit
378
+ - `options.truncateDescription` - Description character limit
379
+
380
+ **Returns:** SEO hooks object with methods
381
+
382
+ ### SEO Hooks Methods
383
+
384
+ - `seo.setMetadata(metadata)` - Set page metadata
385
+ - `seo.setTitle(title)` - Set page title
386
+ - `seo.setDescription(description)` - Set page description
387
+ - `seo.setCanonical(url)` - Set canonical URL
388
+ - `seo.addAlternate(options)` - Add alternate language URL
389
+ - `seo.addSchema(schema)` - Add JSON-LD schema
390
+ - `seo.setLanguage(lang)` - Set page language
391
+ - `seo.setDirection(dir)` - Set text direction
392
+
393
+ ### createSitemap(options)
394
+
395
+ Create a sitemap generator.
396
+
397
+ **Parameters:**
398
+ - `options.siteUrl` - Base site URL
399
+ - `options.changefreq` - Default change frequency
400
+ - `options.priority` - Default priority
401
+ - `options.lastmod` - Default last modified date
402
+
403
+ **Returns:** Sitemap generator object
404
+
405
+ ### createRobotsTxt(options)
406
+
407
+ Create a robots.txt generator.
408
+
409
+ **Parameters:**
410
+ - `options.userAgent` - Default user agent
411
+ - `options.allow` - Allowed paths
412
+ - `options.disallow` - Disallowed paths
413
+ - `options.sitemap` - Sitemap URL
414
+ - `options.host` - Host URL
415
+
416
+ **Returns:** Robots.txt generator object
417
+
418
+ ## Schema Generators
419
+
420
+ ### createArticleSchema(options)
421
+
422
+ Generate Article JSON-LD schema.
423
+
424
+ **Parameters:**
425
+ - `options.headline` - Article headline
426
+ - `options.description` - Article description
427
+ - `options.author` - Author information
428
+ - `options.datePublished` - Publication date
429
+ - `options.dateModified` - Modification date
430
+ - `options.image` - Featured image
431
+ - `options.keywords` - Article keywords
432
+ - `options.articleBody` - Article content
433
+
434
+ ### createBreadcrumbSchema(breadcrumbs)
435
+
436
+ Generate Breadcrumb JSON-LD schema.
437
+
438
+ **Parameters:**
439
+ - `breadcrumbs` - Array of breadcrumb objects with name and url
440
+
441
+ ### createProductSchema(options)
442
+
443
+ Generate Product JSON-LD schema.
444
+
445
+ **Parameters:**
446
+ - `options.name` - Product name
447
+ - `options.description` - Product description
448
+ - `options.image` - Product images
449
+ - `options.offers` - Product offers/pricing
450
+ - `options.brand` - Product brand
451
+ - `options.category` - Product category
452
+ - `options.sku` - Product SKU
453
+
454
+ ## Examples
455
+
456
+ ### Blog with Full SEO
457
+
458
+ ```javascript
459
+ import {
460
+ createSEOHooks,
461
+ createArticleSchema,
462
+ createBreadcrumbSchema
463
+ } from '@coherent.js/seo';
464
+
465
+ const seo = createSEOHooks({
466
+ siteUrl: 'https://myblog.com',
467
+ defaultTitle: 'My Blog',
468
+ titleTemplate: '%s | My Blog'
469
+ });
470
+
471
+ function BlogPost({ post }) {
472
+ // Set basic metadata
473
+ seo.setMetadata({
474
+ title: post.title,
475
+ description: post.excerpt,
476
+ image: post.featuredImage,
477
+ publishedTime: post.publishedAt,
478
+ modifiedTime: post.updatedAt,
479
+ type: 'article',
480
+ author: post.author.name,
481
+ tags: post.tags
482
+ });
483
+
484
+ // Add structured data
485
+ seo.addSchema(createArticleSchema({
486
+ headline: post.title,
487
+ description: post.excerpt,
488
+ author: {
489
+ name: post.author.name,
490
+ url: `/authors/${post.author.slug}`
491
+ },
492
+ datePublished: post.publishedAt,
493
+ dateModified: post.updatedAt,
494
+ image: post.featuredImage,
495
+ keywords: post.tags,
496
+ articleBody: post.content
497
+ }));
498
+
499
+ // Add breadcrumbs
500
+ seo.addSchema(createBreadcrumbSchema([
501
+ { name: 'Home', url: '/' },
502
+ { name: 'Blog', url: '/blog' },
503
+ { name: post.title, url: `/blog/${post.slug}` }
504
+ ]));
505
+
506
+ // Set canonical URL
507
+ seo.setCanonical(`https://myblog.com/blog/${post.slug}`);
508
+
509
+ return {
510
+ article: {
511
+ className: 'blog-post',
512
+ children: [
513
+ { h1: { text: post.title } },
514
+ {
515
+ div: {
516
+ className: 'post-meta',
517
+ children: [
518
+ { span: { text: `By ${post.author.name}` } },
519
+ { time: {
520
+ text: formatDate(post.publishedAt),
521
+ datetime: post.publishedAt
522
+ }}
523
+ ]
524
+ }
525
+ },
526
+ { div: {
527
+ className: 'post-content',
528
+ innerHTML: post.content
529
+ }}
530
+ ]
531
+ }
532
+ };
533
+ }
534
+ ```
535
+
536
+ ### E-commerce Product Page
537
+
538
+ ```javascript
539
+ import {
540
+ createSEOHooks,
541
+ createProductSchema
542
+ } from '@coherent.js/seo';
543
+
544
+ const seo = createSEOHooks({
545
+ siteUrl: 'https://mystore.com'
546
+ });
547
+
548
+ function ProductPage({ product, reviews }) {
549
+ // Basic SEO metadata
550
+ seo.setMetadata({
551
+ title: `${product.name} | My Store`,
552
+ description: product.description,
553
+ image: product.images[0],
554
+ type: 'product.item',
555
+
556
+ // Open Graph for social sharing
557
+ og: {
558
+ price: {
559
+ amount: product.price.toString(),
560
+ currency: product.currency
561
+ },
562
+ availability: product.inStock ? 'instock' : 'outofstock',
563
+ condition: 'new'
564
+ },
565
+
566
+ // Twitter Card
567
+ twitter: {
568
+ card: 'summary_large_image',
569
+ label1: 'Price',
570
+ data1: `${product.currency} ${product.price}`,
571
+ label2: 'Availability',
572
+ data2: product.inStock ? 'In Stock' : 'Out of Stock'
573
+ }
574
+ });
575
+
576
+ // Product structured data
577
+ seo.addSchema(createProductSchema({
578
+ name: product.name,
579
+ description: product.description,
580
+ image: product.images,
581
+ offers: {
582
+ price: product.price.toString(),
583
+ priceCurrency: product.currency,
584
+ availability: product.inStock ? 'InStock' : 'OutOfStock',
585
+ url: `https://mystore.com/products/${product.slug}`,
586
+ seller: {
587
+ name: 'My Store'
588
+ }
589
+ },
590
+ brand: product.brand,
591
+ category: product.category,
592
+ sku: product.sku,
593
+ gtin: product.gtin,
594
+ aggregateRating: {
595
+ ratingValue: reviews.averageRating,
596
+ reviewCount: reviews.count
597
+ }
598
+ }));
599
+
600
+ // Set canonical and alternates
601
+ seo.setCanonical(`https://mystore.com/products/${product.slug}`);
602
+
603
+ return {
604
+ div: {
605
+ className: 'product-page',
606
+ children: [
607
+ { h1: { text: product.name } },
608
+ {
609
+ div: {
610
+ className: 'product-images',
611
+ children: product.images.map(img => ({
612
+ img: { src: img, alt: product.name }
613
+ }))
614
+ }
615
+ },
616
+ { p: { text: product.description } },
617
+ { p: { text: `${product.currency} ${product.price}` } },
618
+ {
619
+ button: {
620
+ text: product.inStock ? 'Add to Cart' : 'Out of Stock',
621
+ disabled: !product.inStock
622
+ }
623
+ }
624
+ ]
625
+ }
626
+ };
627
+ }
628
+ ```
629
+
630
+ ## Best Practices
631
+
632
+ ### 1. Unique Titles and Descriptions
633
+
634
+ ```javascript
635
+ // Good: Unique for each page
636
+ seo.setMetadata({
637
+ title: `How to Master Coherent.js | Developer Guide`,
638
+ description: 'Learn advanced techniques for building high-performance Coherent.js applications with this comprehensive guide.'
639
+ });
640
+
641
+ // Avoid: Generic/duplicated content
642
+ seo.setMetadata({
643
+ title: 'Page Title',
644
+ description: 'This is a description'
645
+ });
646
+ ```
647
+
648
+ ### 2. Optimal Lengths
649
+
650
+ ```javascript
651
+ // Title: 50-60 characters
652
+ // Description: 150-160 characters
653
+ seo.setMetadata({
654
+ title: 'Coherent.js Performance Optimization Guide', // 42 chars - good
655
+ description: 'Maximize your Coherent.js application performance with these proven optimization techniques and best practices.' // 117 chars - good
656
+ });
657
+ ```
658
+
659
+ ### 3. Image Optimization
660
+
661
+ ```javascript
662
+ seo.setMetadata({
663
+ // Use appropriately sized images
664
+ image: {
665
+ url: 'https://example.com/social-image.jpg',
666
+ width: 1200,
667
+ height: 630,
668
+ alt: 'Description of image content'
669
+ }
670
+ });
671
+ ```
672
+
673
+ ## Related Packages
674
+
675
+ - [@coherent.js/core](../core/README.md) - Core framework
676
+ - [@coherent.js/i18n](../i18n/README.md) - Internationalization
677
+ - [@coherent.js/client](../client/README.md) - Client-side utilities
678
+
679
+ ## License
680
+
681
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coherent.js/seo",
3
- "version": "1.0.0-beta.3",
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.3"
23
+ "@coherent.js/core": "1.0.0-beta.6"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",
@@ -35,6 +35,7 @@
35
35
  "README.md",
36
36
  "types/"
37
37
  ],
38
+ "sideEffects": false,
38
39
  "scripts": {
39
40
  "build": "node build.mjs",
40
41
  "clean": "rm -rf dist"
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
+ }