@flightdev/seo 0.2.0
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/LICENSE +21 -0
- package/README.md +403 -0
- package/dist/index.d.ts +282 -0
- package/dist/index.js +1239 -0
- package/dist/index.js.map +1 -0
- package/dist/json-ld/index.d.ts +341 -0
- package/dist/json-ld/index.js +82 -0
- package/dist/json-ld/index.js.map +1 -0
- package/dist/react/index.d.ts +161 -0
- package/dist/react/index.js +1300 -0
- package/dist/react/index.js.map +1 -0
- package/dist/robots/index.d.ts +105 -0
- package/dist/robots/index.js +186 -0
- package/dist/robots/index.js.map +1 -0
- package/dist/sitemap/index.d.ts +224 -0
- package/dist/sitemap/index.js +242 -0
- package/dist/sitemap/index.js.map +1 -0
- package/dist/solid/index.d.ts +50 -0
- package/dist/solid/index.js +1217 -0
- package/dist/solid/index.js.map +1 -0
- package/dist/svelte/index.d.ts +131 -0
- package/dist/svelte/index.js +1253 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/types-BBIMJIqz.d.ts +433 -0
- package/dist/vue/index.d.ts +130 -0
- package/dist/vue/index.js +1293 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +129 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Flight Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# @flight-framework/seo
|
|
2
|
+
|
|
3
|
+
Native SEO and head management for Flight Framework. Zero dependencies, framework-agnostic, SSR-first.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Head Management** - Tag deduplication, ordering, and efficient rendering
|
|
8
|
+
- **Meta Tags** - Basic meta, robots, verification, viewport
|
|
9
|
+
- **Open Graph** - Full OG protocol support including article, product, profile
|
|
10
|
+
- **Twitter Cards** - Summary, large image, app, and player cards
|
|
11
|
+
- **JSON-LD** - Type-safe structured data for rich results
|
|
12
|
+
- **Sitemap Generation** - XML sitemaps with image, video, and news support
|
|
13
|
+
- **robots.txt** - Configurable crawler directives
|
|
14
|
+
- **Framework Integrations** - React, Vue, Solid, Svelte
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @flight-framework/seo
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Core API
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { createSEO, defineMeta } from '@flight-framework/seo';
|
|
28
|
+
|
|
29
|
+
const seo = createSEO({
|
|
30
|
+
baseUrl: 'https://example.com',
|
|
31
|
+
titleTemplate: '%s | My Site',
|
|
32
|
+
defaultTitle: 'My Site',
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const metadata = defineMeta({
|
|
36
|
+
title: 'About Us',
|
|
37
|
+
description: 'Learn more about our company',
|
|
38
|
+
canonical: '/about',
|
|
39
|
+
openGraph: {
|
|
40
|
+
type: 'website',
|
|
41
|
+
images: [{ url: '/og.jpg', width: 1200, height: 630 }],
|
|
42
|
+
},
|
|
43
|
+
twitter: {
|
|
44
|
+
card: 'summary_large_image',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const { html, tags } = seo.render(metadata);
|
|
49
|
+
// Insert `html` into your document head
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### React
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { SEO, JsonLd } from '@flight-framework/seo/react';
|
|
56
|
+
|
|
57
|
+
export default function ProductPage({ product }) {
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
<SEO
|
|
61
|
+
title={product.name}
|
|
62
|
+
description={product.description}
|
|
63
|
+
openGraph={{
|
|
64
|
+
type: 'product',
|
|
65
|
+
images: [{ url: product.image }],
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
<JsonLd
|
|
69
|
+
data={{
|
|
70
|
+
'@type': 'Product',
|
|
71
|
+
name: product.name,
|
|
72
|
+
offers: {
|
|
73
|
+
'@type': 'Offer',
|
|
74
|
+
price: product.price,
|
|
75
|
+
priceCurrency: 'USD',
|
|
76
|
+
},
|
|
77
|
+
}}
|
|
78
|
+
/>
|
|
79
|
+
<main>{/* Page content */}</main>
|
|
80
|
+
</>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Vue
|
|
86
|
+
|
|
87
|
+
```vue
|
|
88
|
+
<script setup>
|
|
89
|
+
import { useSEO, useJsonLd } from '@flight-framework/seo/vue';
|
|
90
|
+
|
|
91
|
+
const product = defineProps(['product']);
|
|
92
|
+
|
|
93
|
+
useSEO({
|
|
94
|
+
title: product.name,
|
|
95
|
+
description: product.description,
|
|
96
|
+
openGraph: {
|
|
97
|
+
type: 'product',
|
|
98
|
+
images: [{ url: product.image }],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
useJsonLd({
|
|
103
|
+
'@type': 'Product',
|
|
104
|
+
name: product.name,
|
|
105
|
+
offers: {
|
|
106
|
+
'@type': 'Offer',
|
|
107
|
+
price: product.price,
|
|
108
|
+
priceCurrency: 'USD',
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
</script>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Solid
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import { SEO, JsonLd } from '@flight-framework/seo/solid';
|
|
118
|
+
|
|
119
|
+
export default function ProductPage(props) {
|
|
120
|
+
return (
|
|
121
|
+
<>
|
|
122
|
+
<SEO
|
|
123
|
+
title={props.product.name}
|
|
124
|
+
description={props.product.description}
|
|
125
|
+
/>
|
|
126
|
+
<JsonLd data={{ '@type': 'Product', name: props.product.name }} />
|
|
127
|
+
<main>...</main>
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Svelte
|
|
134
|
+
|
|
135
|
+
```svelte
|
|
136
|
+
<script>
|
|
137
|
+
import { generateMetadataHtml, createJsonLdScript } from '@flight-framework/seo/svelte';
|
|
138
|
+
|
|
139
|
+
export let product;
|
|
140
|
+
</script>
|
|
141
|
+
|
|
142
|
+
<svelte:head>
|
|
143
|
+
{@html generateMetadataHtml({
|
|
144
|
+
title: product.name,
|
|
145
|
+
description: product.description,
|
|
146
|
+
openGraph: { type: 'product' }
|
|
147
|
+
})}
|
|
148
|
+
{@html createJsonLdScript({
|
|
149
|
+
'@type': 'Product',
|
|
150
|
+
name: product.name
|
|
151
|
+
})}
|
|
152
|
+
</svelte:head>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## API Reference
|
|
156
|
+
|
|
157
|
+
### createSEO(config?)
|
|
158
|
+
|
|
159
|
+
Create an SEO service instance.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const seo = createSEO({
|
|
163
|
+
baseUrl: 'https://example.com',
|
|
164
|
+
titleTemplate: '%s | My Site',
|
|
165
|
+
defaultTitle: 'My Site',
|
|
166
|
+
defaultOpenGraph: {
|
|
167
|
+
siteName: 'My Site',
|
|
168
|
+
locale: 'en_US',
|
|
169
|
+
},
|
|
170
|
+
defaultTwitter: {
|
|
171
|
+
site: '@mysite',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### defineMeta(metadata)
|
|
177
|
+
|
|
178
|
+
Type-safe metadata definition.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const metadata = defineMeta({
|
|
182
|
+
title: 'Page Title',
|
|
183
|
+
description: 'Page description',
|
|
184
|
+
keywords: ['keyword1', 'keyword2'],
|
|
185
|
+
author: 'Author Name',
|
|
186
|
+
canonical: 'https://example.com/page',
|
|
187
|
+
robots: { index: true, follow: true },
|
|
188
|
+
openGraph: { /* ... */ },
|
|
189
|
+
twitter: { /* ... */ },
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Metadata Types
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface Metadata {
|
|
197
|
+
// Basic
|
|
198
|
+
title?: string;
|
|
199
|
+
titleTemplate?: string;
|
|
200
|
+
description?: string;
|
|
201
|
+
keywords?: string | string[];
|
|
202
|
+
author?: string;
|
|
203
|
+
canonical?: string;
|
|
204
|
+
|
|
205
|
+
// Robots
|
|
206
|
+
robots?: RobotsMeta | string;
|
|
207
|
+
googleBot?: RobotsMeta | string;
|
|
208
|
+
|
|
209
|
+
// Open Graph
|
|
210
|
+
openGraph?: {
|
|
211
|
+
type?: 'website' | 'article' | 'product' | ...;
|
|
212
|
+
title?: string;
|
|
213
|
+
description?: string;
|
|
214
|
+
url?: string;
|
|
215
|
+
siteName?: string;
|
|
216
|
+
locale?: string;
|
|
217
|
+
images?: OpenGraphImage[];
|
|
218
|
+
article?: OpenGraphArticle;
|
|
219
|
+
product?: OpenGraphProduct;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Twitter
|
|
223
|
+
twitter?: {
|
|
224
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
225
|
+
title?: string;
|
|
226
|
+
description?: string;
|
|
227
|
+
site?: string;
|
|
228
|
+
creator?: string;
|
|
229
|
+
image?: TwitterCardImage | string;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## JSON-LD Structured Data
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import {
|
|
238
|
+
createJsonLd,
|
|
239
|
+
articleJsonLd,
|
|
240
|
+
productJsonLd,
|
|
241
|
+
breadcrumbJsonLd,
|
|
242
|
+
faqJsonLd,
|
|
243
|
+
} from '@flight-framework/seo/json-ld';
|
|
244
|
+
|
|
245
|
+
// Generic
|
|
246
|
+
const jsonLd = createJsonLd({
|
|
247
|
+
'@type': 'Organization',
|
|
248
|
+
name: 'My Company',
|
|
249
|
+
url: 'https://example.com',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Article
|
|
253
|
+
const article = articleJsonLd({
|
|
254
|
+
headline: 'Article Title',
|
|
255
|
+
datePublished: '2026-01-10',
|
|
256
|
+
author: { '@type': 'Person', name: 'Author' },
|
|
257
|
+
publisher: { '@type': 'Organization', name: 'Publisher' },
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Product
|
|
261
|
+
const product = productJsonLd({
|
|
262
|
+
name: 'Widget',
|
|
263
|
+
description: 'A great widget',
|
|
264
|
+
offers: {
|
|
265
|
+
'@type': 'Offer',
|
|
266
|
+
price: 9.99,
|
|
267
|
+
priceCurrency: 'USD',
|
|
268
|
+
availability: 'InStock',
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Breadcrumb
|
|
273
|
+
const breadcrumb = breadcrumbJsonLd([
|
|
274
|
+
{ name: 'Home', url: '/' },
|
|
275
|
+
{ name: 'Products', url: '/products' },
|
|
276
|
+
{ name: 'Widget' },
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
// FAQ
|
|
280
|
+
const faq = faqJsonLd([
|
|
281
|
+
{ question: 'What is this?', answer: 'A great product.' },
|
|
282
|
+
{ question: 'How much?', answer: '$9.99' },
|
|
283
|
+
]);
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Sitemap Generation
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { createSitemap, createSitemapIndex } from '@flight-framework/seo/sitemap';
|
|
290
|
+
|
|
291
|
+
const sitemap = createSitemap({
|
|
292
|
+
baseUrl: 'https://example.com',
|
|
293
|
+
pretty: true,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Add URLs
|
|
297
|
+
sitemap.add('/', { priority: 1.0, changefreq: 'daily' });
|
|
298
|
+
sitemap.add('/about', { priority: 0.8 });
|
|
299
|
+
sitemap.add('/products/widget', {
|
|
300
|
+
lastmod: new Date(),
|
|
301
|
+
priority: 0.7,
|
|
302
|
+
images: [{ loc: '/images/widget.jpg', title: 'Widget' }],
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// Generate XML
|
|
306
|
+
const xml = sitemap.generate();
|
|
307
|
+
|
|
308
|
+
// For large sites, use sitemap index
|
|
309
|
+
const index = createSitemapIndex();
|
|
310
|
+
index.add('https://example.com/sitemap-1.xml');
|
|
311
|
+
index.add('https://example.com/sitemap-2.xml');
|
|
312
|
+
const indexXml = index.generate();
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## robots.txt Generation
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { createRobots, standardRobots } from '@flight-framework/seo/robots';
|
|
319
|
+
|
|
320
|
+
// Custom
|
|
321
|
+
const robots = createRobots();
|
|
322
|
+
robots.allow('*', '/');
|
|
323
|
+
robots.disallow('*', '/admin');
|
|
324
|
+
robots.disallow('*', '/api');
|
|
325
|
+
robots.addSitemap('https://example.com/sitemap.xml');
|
|
326
|
+
const txt = robots.generate();
|
|
327
|
+
|
|
328
|
+
// Standard preset
|
|
329
|
+
const standard = standardRobots({
|
|
330
|
+
sitemapUrl: 'https://example.com/sitemap.xml',
|
|
331
|
+
blockPaths: ['/private'],
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## SSR Integration
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// In your server entry
|
|
339
|
+
import { createSEO, createHeadManager } from '@flight-framework/seo';
|
|
340
|
+
|
|
341
|
+
const seo = createSEO({ baseUrl: 'https://example.com' });
|
|
342
|
+
|
|
343
|
+
export function render(url: string, metadata: Metadata): string {
|
|
344
|
+
const { html: headHtml } = seo.render(metadata);
|
|
345
|
+
|
|
346
|
+
return `
|
|
347
|
+
<!DOCTYPE html>
|
|
348
|
+
<html>
|
|
349
|
+
<head>
|
|
350
|
+
${headHtml}
|
|
351
|
+
</head>
|
|
352
|
+
<body>
|
|
353
|
+
<!-- app content -->
|
|
354
|
+
</body>
|
|
355
|
+
</html>
|
|
356
|
+
`;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Dynamic Metadata
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// src/routes/products/[id].page.tsx
|
|
364
|
+
import { defineMeta } from '@flight-framework/seo';
|
|
365
|
+
|
|
366
|
+
export async function generateMetadata({ params }) {
|
|
367
|
+
const product = await getProduct(params.id);
|
|
368
|
+
|
|
369
|
+
return defineMeta({
|
|
370
|
+
title: product.name,
|
|
371
|
+
description: product.description,
|
|
372
|
+
openGraph: {
|
|
373
|
+
type: 'product',
|
|
374
|
+
images: [{ url: product.image }],
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export default function ProductPage({ product }) {
|
|
380
|
+
return <main>{/* content */}</main>;
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Best Practices
|
|
385
|
+
|
|
386
|
+
1. **Always set title and description** - These are essential for SEO
|
|
387
|
+
2. **Use canonical URLs** - Prevent duplicate content issues
|
|
388
|
+
3. **Provide Open Graph images** - 1200x630px recommended for social sharing
|
|
389
|
+
4. **Add structured data** - Improves rich results in search
|
|
390
|
+
5. **Generate sitemaps** - Help search engines discover your pages
|
|
391
|
+
6. **Configure robots.txt** - Control crawler access
|
|
392
|
+
|
|
393
|
+
## Related
|
|
394
|
+
|
|
395
|
+
- [Flight Framework](https://github.com/flight-framework/flight)
|
|
396
|
+
- [Open Graph Protocol](https://ogp.me/)
|
|
397
|
+
- [Twitter Cards](https://developer.twitter.com/en/docs/twitter-for-websites/cards)
|
|
398
|
+
- [Schema.org](https://schema.org/)
|
|
399
|
+
- [Google Rich Results](https://search.google.com/test/rich-results)
|
|
400
|
+
|
|
401
|
+
## License
|
|
402
|
+
|
|
403
|
+
MIT License
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { H as HtmlTag, R as RenderedHead, M as Metadata, V as VerificationMeta, O as OpenGraphMeta, T as TwitterCardMeta, S as SEOConfig, a as SEOService } from './types-BBIMJIqz.js';
|
|
2
|
+
export { A as AlternateLink, I as IconMeta, h as OpenGraphArticle, g as OpenGraphAudio, j as OpenGraphBook, e as OpenGraphImage, k as OpenGraphProduct, i as OpenGraphProfile, d as OpenGraphType, f as OpenGraphVideo, b as ResolvedMetadata, c as RobotsMeta, o as TwitterCardApp, m as TwitterCardImage, n as TwitterCardPlayer, l as TwitterCardType } from './types-BBIMJIqz.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @flightdev/seo - Head Manager
|
|
6
|
+
*
|
|
7
|
+
* Server-side head management with tag deduplication,
|
|
8
|
+
* ordering, and efficient rendering.
|
|
9
|
+
*
|
|
10
|
+
* Designed for SSR-first with O(1) deduplication.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Head Manager for SSR
|
|
15
|
+
*
|
|
16
|
+
* Manages head tags with:
|
|
17
|
+
* - O(1) deduplication using Map
|
|
18
|
+
* - Deterministic ordering
|
|
19
|
+
* - Efficient string concatenation
|
|
20
|
+
*/
|
|
21
|
+
declare class HeadManager {
|
|
22
|
+
private tags;
|
|
23
|
+
private frozen;
|
|
24
|
+
/**
|
|
25
|
+
* Add a tag to the head
|
|
26
|
+
*/
|
|
27
|
+
addTag(tag: HtmlTag): this;
|
|
28
|
+
/**
|
|
29
|
+
* Add multiple tags
|
|
30
|
+
*/
|
|
31
|
+
addTags(tags: HtmlTag[]): this;
|
|
32
|
+
/**
|
|
33
|
+
* Remove a tag by key
|
|
34
|
+
*/
|
|
35
|
+
removeTag(key: string): this;
|
|
36
|
+
/**
|
|
37
|
+
* Check if a tag exists
|
|
38
|
+
*/
|
|
39
|
+
hasTag(key: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Get a tag by key
|
|
42
|
+
*/
|
|
43
|
+
getTag(key: string): HtmlTag | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Get all tags
|
|
46
|
+
*/
|
|
47
|
+
getTags(): HtmlTag[];
|
|
48
|
+
/**
|
|
49
|
+
* Clear all tags
|
|
50
|
+
*/
|
|
51
|
+
clear(): this;
|
|
52
|
+
/**
|
|
53
|
+
* Freeze the manager (no more modifications)
|
|
54
|
+
*/
|
|
55
|
+
freeze(): this;
|
|
56
|
+
/**
|
|
57
|
+
* Check if frozen
|
|
58
|
+
*/
|
|
59
|
+
isFrozen(): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Render all tags to HTML
|
|
62
|
+
*/
|
|
63
|
+
render(): RenderedHead;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Render a single tag to HTML
|
|
67
|
+
*/
|
|
68
|
+
declare function renderTag(tag: HtmlTag): string;
|
|
69
|
+
/**
|
|
70
|
+
* Render multiple tags to HTML
|
|
71
|
+
*/
|
|
72
|
+
declare function renderTags(tags: HtmlTag[]): string;
|
|
73
|
+
/**
|
|
74
|
+
* Create a new HeadManager instance
|
|
75
|
+
*/
|
|
76
|
+
declare function createHeadManager(): HeadManager;
|
|
77
|
+
/**
|
|
78
|
+
* SSR head context for passing data between components
|
|
79
|
+
*/
|
|
80
|
+
interface HeadContext {
|
|
81
|
+
manager: HeadManager;
|
|
82
|
+
metadata: Metadata;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Set the current head context (call at request start)
|
|
86
|
+
*/
|
|
87
|
+
declare function setHeadContext(context: HeadContext): void;
|
|
88
|
+
/**
|
|
89
|
+
* Get the current head context
|
|
90
|
+
*/
|
|
91
|
+
declare function getHeadContext(): HeadContext | null;
|
|
92
|
+
/**
|
|
93
|
+
* Clear the current head context (call at request end)
|
|
94
|
+
*/
|
|
95
|
+
declare function clearHeadContext(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Run a function with a head context
|
|
98
|
+
*/
|
|
99
|
+
declare function withHeadContext<T>(context: HeadContext, fn: () => T): T;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @flightdev/seo - Meta Tag Generation
|
|
103
|
+
*
|
|
104
|
+
* Generates meta tags from Metadata configuration.
|
|
105
|
+
* Handles basic meta, robots, viewport, and verification tags.
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generate title tag
|
|
110
|
+
*/
|
|
111
|
+
declare function generateTitleTag(title: string | undefined, template?: string, defaultTitle?: string): HtmlTag | null;
|
|
112
|
+
/**
|
|
113
|
+
* Generate charset meta tag
|
|
114
|
+
*/
|
|
115
|
+
declare function generateCharsetTag(charset?: string): HtmlTag;
|
|
116
|
+
/**
|
|
117
|
+
* Generate viewport meta tag
|
|
118
|
+
*/
|
|
119
|
+
declare function generateViewportTag(viewport: Metadata['viewport']): HtmlTag | null;
|
|
120
|
+
/**
|
|
121
|
+
* Generate description meta tag
|
|
122
|
+
*/
|
|
123
|
+
declare function generateDescriptionTag(description: string | undefined): HtmlTag | null;
|
|
124
|
+
/**
|
|
125
|
+
* Generate keywords meta tag
|
|
126
|
+
*/
|
|
127
|
+
declare function generateKeywordsTag(keywords: string | string[] | undefined): HtmlTag | null;
|
|
128
|
+
/**
|
|
129
|
+
* Generate author meta tag
|
|
130
|
+
*/
|
|
131
|
+
declare function generateAuthorTag(author: string | undefined): HtmlTag | null;
|
|
132
|
+
/**
|
|
133
|
+
* Generate theme-color meta tag(s)
|
|
134
|
+
*/
|
|
135
|
+
declare function generateThemeColorTags(themeColor: Metadata['themeColor']): HtmlTag[];
|
|
136
|
+
/**
|
|
137
|
+
* Generate robots meta tag
|
|
138
|
+
*/
|
|
139
|
+
declare function generateRobotsTag(robots: Metadata['robots']): HtmlTag | null;
|
|
140
|
+
/**
|
|
141
|
+
* Generate googlebot meta tag
|
|
142
|
+
*/
|
|
143
|
+
declare function generateGooglebotTag(googleBot: Metadata['googleBot']): HtmlTag | null;
|
|
144
|
+
/**
|
|
145
|
+
* Generate verification meta tags
|
|
146
|
+
*/
|
|
147
|
+
declare function generateVerificationTags(verification: VerificationMeta | undefined): HtmlTag[];
|
|
148
|
+
/**
|
|
149
|
+
* Generate canonical link tag
|
|
150
|
+
*/
|
|
151
|
+
declare function generateCanonicalTag(canonical: string | undefined): HtmlTag | null;
|
|
152
|
+
/**
|
|
153
|
+
* Generate alternate link tags
|
|
154
|
+
*/
|
|
155
|
+
declare function generateAlternateTags(alternates: Metadata['alternates']): HtmlTag[];
|
|
156
|
+
/**
|
|
157
|
+
* Generate all basic meta tags from Metadata
|
|
158
|
+
*/
|
|
159
|
+
declare function generateMetaTags(metadata: Metadata, options?: {
|
|
160
|
+
titleTemplate?: string;
|
|
161
|
+
defaultTitle?: string;
|
|
162
|
+
}): HtmlTag[];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @flightdev/seo - Open Graph Tags
|
|
166
|
+
*
|
|
167
|
+
* Generates Open Graph protocol meta tags for rich social sharing.
|
|
168
|
+
* Supports all OG types: website, article, product, profile, etc.
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Generate all Open Graph meta tags
|
|
173
|
+
*/
|
|
174
|
+
declare function generateOpenGraphTags(og: OpenGraphMeta | undefined): HtmlTag[];
|
|
175
|
+
/**
|
|
176
|
+
* Generate minimal Open Graph tags (for fallback from metadata)
|
|
177
|
+
*/
|
|
178
|
+
declare function generateOpenGraphFallback(title: string | undefined, description: string | undefined, url: string | undefined): HtmlTag[];
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @flightdev/seo - Twitter Card Tags
|
|
182
|
+
*
|
|
183
|
+
* Generates Twitter Card meta tags for rich Twitter sharing.
|
|
184
|
+
* Supports summary, summary_large_image, app, and player cards.
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generate all Twitter Card meta tags
|
|
189
|
+
*/
|
|
190
|
+
declare function generateTwitterTags(twitter: TwitterCardMeta | undefined): HtmlTag[];
|
|
191
|
+
/**
|
|
192
|
+
* Generate minimal Twitter Card tags (for fallback)
|
|
193
|
+
*/
|
|
194
|
+
declare function generateTwitterFallback(title: string | undefined, description: string | undefined, image: string | undefined, cardType?: TwitterCardMeta['card']): HtmlTag[];
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* @flightdev/seo
|
|
198
|
+
*
|
|
199
|
+
* Native SEO and head management for Flight Framework.
|
|
200
|
+
* Zero dependencies, framework-agnostic, SSR-first.
|
|
201
|
+
*
|
|
202
|
+
* Features:
|
|
203
|
+
* - Head management with deduplication
|
|
204
|
+
* - Meta tags (basic, robots, verification)
|
|
205
|
+
* - Open Graph protocol
|
|
206
|
+
* - Twitter Cards
|
|
207
|
+
* - JSON-LD structured data
|
|
208
|
+
* - Sitemap generation
|
|
209
|
+
* - robots.txt generation
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* import { createSEO, defineMeta } from '@flightdev/seo';
|
|
214
|
+
*
|
|
215
|
+
* const seo = createSEO({ baseUrl: 'https://example.com' });
|
|
216
|
+
*
|
|
217
|
+
* const metadata = defineMeta({
|
|
218
|
+
* title: 'My Page',
|
|
219
|
+
* description: 'Page description',
|
|
220
|
+
* openGraph: {
|
|
221
|
+
* type: 'website',
|
|
222
|
+
* images: [{ url: '/og.jpg', width: 1200, height: 630 }],
|
|
223
|
+
* },
|
|
224
|
+
* });
|
|
225
|
+
*
|
|
226
|
+
* const { html } = seo.render(metadata);
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create an SEO service
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* const seo = createSEO({
|
|
236
|
+
* baseUrl: 'https://example.com',
|
|
237
|
+
* titleTemplate: '%s | My Site',
|
|
238
|
+
* defaultTitle: 'My Site',
|
|
239
|
+
* });
|
|
240
|
+
*
|
|
241
|
+
* const { html } = seo.render({
|
|
242
|
+
* title: 'About Us',
|
|
243
|
+
* description: 'Learn more about us',
|
|
244
|
+
* });
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
declare function createSEO(config?: SEOConfig): SEOService;
|
|
248
|
+
/**
|
|
249
|
+
* Define metadata with type safety
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* const metadata = defineMeta({
|
|
254
|
+
* title: 'Product Name',
|
|
255
|
+
* description: 'Product description',
|
|
256
|
+
* openGraph: {
|
|
257
|
+
* type: 'product',
|
|
258
|
+
* images: [{ url: '/product.jpg' }],
|
|
259
|
+
* },
|
|
260
|
+
* });
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
declare function defineMeta(metadata: Metadata): Metadata;
|
|
264
|
+
/**
|
|
265
|
+
* Merge parent and child metadata
|
|
266
|
+
* Child values override parent values
|
|
267
|
+
* Arrays are replaced, not merged
|
|
268
|
+
*/
|
|
269
|
+
declare function mergeMetadata(parent: Metadata, child: Metadata): Metadata;
|
|
270
|
+
/**
|
|
271
|
+
* Type for async metadata generation function
|
|
272
|
+
*/
|
|
273
|
+
type GenerateMetadataFn<TParams = Record<string, string>> = (context: {
|
|
274
|
+
params: TParams;
|
|
275
|
+
searchParams?: Record<string, string | string[]>;
|
|
276
|
+
}) => Metadata | Promise<Metadata>;
|
|
277
|
+
/**
|
|
278
|
+
* Version constant
|
|
279
|
+
*/
|
|
280
|
+
declare const VERSION = "0.1.0";
|
|
281
|
+
|
|
282
|
+
export { type GenerateMetadataFn, type HeadContext, HeadManager, HtmlTag, Metadata, OpenGraphMeta, RenderedHead, SEOConfig, SEOService, TwitterCardMeta, VERSION, VerificationMeta, clearHeadContext, createHeadManager, createSEO, defineMeta, generateAlternateTags, generateAuthorTag, generateCanonicalTag, generateCharsetTag, generateDescriptionTag, generateGooglebotTag, generateKeywordsTag, generateMetaTags, generateOpenGraphFallback, generateOpenGraphTags, generateRobotsTag, generateThemeColorTags, generateTitleTag, generateTwitterFallback, generateTwitterTags, generateVerificationTags, generateViewportTag, getHeadContext, mergeMetadata, renderTag, renderTags, setHeadContext, withHeadContext };
|