@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.
@@ -0,0 +1,433 @@
1
+ /**
2
+ * @flightdev/seo - Type Definitions
3
+ *
4
+ * Core type definitions for SEO, meta tags, Open Graph, Twitter Cards,
5
+ * and structured data. All types are designed for strict TypeScript usage.
6
+ */
7
+ /**
8
+ * Robots meta directives
9
+ */
10
+ interface RobotsMeta {
11
+ /** Allow indexing of this page */
12
+ index?: boolean;
13
+ /** Allow following links on this page */
14
+ follow?: boolean;
15
+ /** Prevent caching of this page */
16
+ noarchive?: boolean;
17
+ /** Prevent snippet generation */
18
+ nosnippet?: boolean;
19
+ /** Prevent translation */
20
+ notranslate?: boolean;
21
+ /** Maximum snippet length (-1 for unlimited, 0 for none) */
22
+ maxSnippet?: number;
23
+ /** Maximum image preview size ('none', 'standard', 'large') */
24
+ maxImagePreview?: 'none' | 'standard' | 'large';
25
+ /** Maximum video preview length in seconds (-1 for unlimited, 0 for none) */
26
+ maxVideoPreview?: number;
27
+ /** Prevent showing in Google News */
28
+ nosnippetFromNews?: boolean;
29
+ /** Unavailable after date (ISO 8601) */
30
+ unavailableAfter?: string;
31
+ }
32
+ /**
33
+ * Alternate link for internationalization or formats
34
+ */
35
+ interface AlternateLink {
36
+ /** Language/region code (e.g., 'en-US', 'es') or 'x-default' */
37
+ hreflang?: string;
38
+ /** Alternate URL */
39
+ href: string;
40
+ /** Media query for responsive alternates */
41
+ media?: string;
42
+ /** MIME type for format alternates */
43
+ type?: string;
44
+ /** Title for the alternate */
45
+ title?: string;
46
+ }
47
+ /**
48
+ * Verification meta tags for search engines
49
+ */
50
+ interface VerificationMeta {
51
+ google?: string;
52
+ bing?: string;
53
+ yandex?: string;
54
+ pinterest?: string;
55
+ norton?: string;
56
+ }
57
+ /**
58
+ * Open Graph image definition
59
+ */
60
+ interface OpenGraphImage {
61
+ /** Image URL (must be absolute) */
62
+ url: string;
63
+ /** Secure URL (https) */
64
+ secureUrl?: string;
65
+ /** Image width in pixels */
66
+ width?: number;
67
+ /** Image height in pixels */
68
+ height?: number;
69
+ /** Alt text for accessibility */
70
+ alt?: string;
71
+ /** MIME type */
72
+ type?: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | string;
73
+ }
74
+ /**
75
+ * Open Graph video definition
76
+ */
77
+ interface OpenGraphVideo {
78
+ /** Video URL */
79
+ url: string;
80
+ /** Secure URL (https) */
81
+ secureUrl?: string;
82
+ /** Video width in pixels */
83
+ width?: number;
84
+ /** Video height in pixels */
85
+ height?: number;
86
+ /** MIME type */
87
+ type?: 'video/mp4' | 'video/webm' | string;
88
+ }
89
+ /**
90
+ * Open Graph audio definition
91
+ */
92
+ interface OpenGraphAudio {
93
+ /** Audio URL */
94
+ url: string;
95
+ /** Secure URL (https) */
96
+ secureUrl?: string;
97
+ /** MIME type */
98
+ type?: 'audio/mpeg' | 'audio/ogg' | string;
99
+ }
100
+ /**
101
+ * Open Graph article-specific properties
102
+ */
103
+ interface OpenGraphArticle {
104
+ /** When the article was first published (ISO 8601) */
105
+ publishedTime?: string;
106
+ /** When the article was last modified (ISO 8601) */
107
+ modifiedTime?: string;
108
+ /** When the article expires (ISO 8601) */
109
+ expirationTime?: string;
110
+ /** Authors of the article */
111
+ authors?: string[];
112
+ /** Article section/category */
113
+ section?: string;
114
+ /** Article tags */
115
+ tags?: string[];
116
+ }
117
+ /**
118
+ * Open Graph profile properties
119
+ */
120
+ interface OpenGraphProfile {
121
+ /** First name */
122
+ firstName?: string;
123
+ /** Last name */
124
+ lastName?: string;
125
+ /** Username */
126
+ username?: string;
127
+ /** Gender */
128
+ gender?: 'male' | 'female';
129
+ }
130
+ /**
131
+ * Open Graph book properties
132
+ */
133
+ interface OpenGraphBook {
134
+ /** Authors of the book */
135
+ authors?: string[];
136
+ /** ISBN */
137
+ isbn?: string;
138
+ /** Release date (ISO 8601) */
139
+ releaseDate?: string;
140
+ /** Book tags */
141
+ tags?: string[];
142
+ }
143
+ /**
144
+ * Open Graph product properties
145
+ */
146
+ interface OpenGraphProduct {
147
+ /** Product price amount */
148
+ priceAmount?: number;
149
+ /** Price currency (ISO 4217) */
150
+ priceCurrency?: string;
151
+ /** Product availability */
152
+ availability?: 'instock' | 'outofstock' | 'preorder' | 'pending';
153
+ /** Product condition */
154
+ condition?: 'new' | 'refurbished' | 'used';
155
+ /** Retailer item ID */
156
+ retailerItemId?: string;
157
+ }
158
+ /**
159
+ * Open Graph type
160
+ */
161
+ type OpenGraphType = 'website' | 'article' | 'book' | 'profile' | 'music.song' | 'music.album' | 'music.playlist' | 'music.radio_station' | 'video.movie' | 'video.episode' | 'video.tv_show' | 'video.other' | 'product' | string;
162
+ /**
163
+ * Complete Open Graph metadata
164
+ */
165
+ interface OpenGraphMeta {
166
+ /** Content type */
167
+ type?: OpenGraphType;
168
+ /** Page title */
169
+ title?: string;
170
+ /** Page description */
171
+ description?: string;
172
+ /** Canonical URL */
173
+ url?: string;
174
+ /** Site name */
175
+ siteName?: string;
176
+ /** Locale (e.g., 'en_US') */
177
+ locale?: string;
178
+ /** Alternate locales */
179
+ alternateLocales?: string[];
180
+ /** Images */
181
+ images?: OpenGraphImage[];
182
+ /** Videos */
183
+ videos?: OpenGraphVideo[];
184
+ /** Audio */
185
+ audio?: OpenGraphAudio[];
186
+ /** Determiner ('a', 'an', 'the', '', 'auto') */
187
+ determiner?: 'a' | 'an' | 'the' | '' | 'auto';
188
+ /** Article-specific properties */
189
+ article?: OpenGraphArticle;
190
+ /** Profile-specific properties */
191
+ profile?: OpenGraphProfile;
192
+ /** Book-specific properties */
193
+ book?: OpenGraphBook;
194
+ /** Product-specific properties */
195
+ product?: OpenGraphProduct;
196
+ }
197
+ /**
198
+ * Twitter Card type
199
+ */
200
+ type TwitterCardType = 'summary' | 'summary_large_image' | 'app' | 'player';
201
+ /**
202
+ * Twitter Card image
203
+ */
204
+ interface TwitterCardImage {
205
+ /** Image URL */
206
+ url: string;
207
+ /** Alt text */
208
+ alt?: string;
209
+ }
210
+ /**
211
+ * Twitter Card player (for player cards)
212
+ */
213
+ interface TwitterCardPlayer {
214
+ /** Player URL */
215
+ url: string;
216
+ /** Player width */
217
+ width: number;
218
+ /** Player height */
219
+ height: number;
220
+ /** Stream URL */
221
+ stream?: string;
222
+ }
223
+ /**
224
+ * Twitter Card app (for app cards)
225
+ */
226
+ interface TwitterCardApp {
227
+ /** App name */
228
+ name: string;
229
+ /** App ID */
230
+ id: {
231
+ iphone?: string;
232
+ ipad?: string;
233
+ googleplay?: string;
234
+ };
235
+ /** App URL */
236
+ url?: {
237
+ iphone?: string;
238
+ ipad?: string;
239
+ googleplay?: string;
240
+ };
241
+ }
242
+ /**
243
+ * Complete Twitter Card metadata
244
+ */
245
+ interface TwitterCardMeta {
246
+ /** Card type */
247
+ card?: TwitterCardType;
248
+ /** Page title (max 70 chars) */
249
+ title?: string;
250
+ /** Page description (max 200 chars) */
251
+ description?: string;
252
+ /** Site Twitter handle (e.g., '@example') */
253
+ site?: string;
254
+ /** Site ID */
255
+ siteId?: string;
256
+ /** Creator Twitter handle */
257
+ creator?: string;
258
+ /** Creator ID */
259
+ creatorId?: string;
260
+ /** Card image */
261
+ image?: TwitterCardImage | string;
262
+ /** Additional images */
263
+ images?: TwitterCardImage[];
264
+ /** Player card data */
265
+ player?: TwitterCardPlayer;
266
+ /** App card data */
267
+ app?: TwitterCardApp;
268
+ /** Custom labels (for large image cards) */
269
+ label1?: string;
270
+ data1?: string;
271
+ label2?: string;
272
+ data2?: string;
273
+ }
274
+ /**
275
+ * Icon definition
276
+ */
277
+ interface IconMeta {
278
+ /** Icon URL */
279
+ url: string;
280
+ /** Icon type */
281
+ type?: string;
282
+ /** Icon sizes (e.g., '32x32', '180x180') */
283
+ sizes?: string;
284
+ /** Icon purpose for web manifest */
285
+ purpose?: 'any' | 'maskable' | 'monochrome';
286
+ }
287
+ /**
288
+ * Complete page metadata
289
+ */
290
+ interface Metadata {
291
+ /** Page title */
292
+ title?: string;
293
+ /** Title template (e.g., '%s | My Site') */
294
+ titleTemplate?: string;
295
+ /** Default title when page title is empty */
296
+ defaultTitle?: string;
297
+ /** Page description */
298
+ description?: string;
299
+ /** Keywords (generally not used by search engines anymore) */
300
+ keywords?: string | string[];
301
+ /** Author name */
302
+ author?: string;
303
+ /** Generator (e.g., 'Flight Framework') */
304
+ generator?: string;
305
+ /** Application name */
306
+ applicationName?: string;
307
+ /** Referrer policy */
308
+ referrer?: 'no-referrer' | 'origin' | 'no-referrer-when-downgrade' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
309
+ /** Theme color */
310
+ themeColor?: string | {
311
+ media: string;
312
+ color: string;
313
+ }[];
314
+ /** Color scheme */
315
+ colorScheme?: 'light' | 'dark' | 'light dark' | 'dark light' | 'only light';
316
+ /** Viewport configuration */
317
+ viewport?: string | {
318
+ width?: number | 'device-width';
319
+ height?: number | 'device-height';
320
+ initialScale?: number;
321
+ minimumScale?: number;
322
+ maximumScale?: number;
323
+ userScalable?: boolean;
324
+ viewportFit?: 'auto' | 'contain' | 'cover';
325
+ };
326
+ /** Charset (default: 'utf-8') */
327
+ charset?: string;
328
+ /** Canonical URL */
329
+ canonical?: string;
330
+ /** Alternate links (hreflang, RSS, etc.) */
331
+ alternates?: AlternateLink[];
332
+ /** Base URL for relative URLs */
333
+ base?: string;
334
+ /** Robots directives */
335
+ robots?: RobotsMeta | string;
336
+ /** Google-specific robots */
337
+ googleBot?: RobotsMeta | string;
338
+ /** Search engine verification */
339
+ verification?: VerificationMeta;
340
+ /** Open Graph metadata */
341
+ openGraph?: OpenGraphMeta;
342
+ /** Twitter Card metadata */
343
+ twitter?: TwitterCardMeta;
344
+ /** Apple-specific metadata */
345
+ apple?: {
346
+ /** Apple touch icon */
347
+ touchIcon?: string | IconMeta;
348
+ /** Web app capable */
349
+ mobileWebAppCapable?: boolean;
350
+ /** Status bar style */
351
+ statusBarStyle?: 'default' | 'black' | 'black-translucent';
352
+ /** App title */
353
+ title?: string;
354
+ };
355
+ /** Favicon */
356
+ icons?: {
357
+ icon?: string | IconMeta | (string | IconMeta)[];
358
+ shortcut?: string | IconMeta;
359
+ apple?: string | IconMeta | (string | IconMeta)[];
360
+ other?: IconMeta[];
361
+ };
362
+ /** Web manifest URL */
363
+ manifest?: string;
364
+ /** Additional meta tags */
365
+ other?: Record<string, string>;
366
+ }
367
+ /**
368
+ * Metadata with resolved values (after template processing)
369
+ */
370
+ interface ResolvedMetadata extends Metadata {
371
+ /** Fully resolved title (after template application) */
372
+ resolvedTitle?: string;
373
+ }
374
+ /**
375
+ * HTML tag definition for rendering
376
+ */
377
+ interface HtmlTag {
378
+ /** Tag name (e.g., 'meta', 'link', 'title') */
379
+ tag: 'title' | 'meta' | 'link' | 'script' | 'base';
380
+ /** Tag attributes */
381
+ attrs?: Record<string, string | boolean | undefined>;
382
+ /** Tag content (for title, script) */
383
+ content?: string;
384
+ /** Unique key for deduplication */
385
+ key?: string;
386
+ }
387
+ /**
388
+ * Rendered head result
389
+ */
390
+ interface RenderedHead {
391
+ /** All generated HTML tags */
392
+ tags: HtmlTag[];
393
+ /** Rendered HTML string */
394
+ html: string;
395
+ }
396
+ /**
397
+ * SEO service configuration
398
+ */
399
+ interface SEOConfig {
400
+ /** Base URL for canonical URLs */
401
+ baseUrl?: string;
402
+ /** Default title template */
403
+ titleTemplate?: string;
404
+ /** Default title */
405
+ defaultTitle?: string;
406
+ /** Default Open Graph data */
407
+ defaultOpenGraph?: Partial<OpenGraphMeta>;
408
+ /** Default Twitter Card data */
409
+ defaultTwitter?: Partial<TwitterCardMeta>;
410
+ /** Enable/disable specific features */
411
+ features?: {
412
+ openGraph?: boolean;
413
+ twitter?: boolean;
414
+ robots?: boolean;
415
+ };
416
+ }
417
+ /**
418
+ * SEO service interface
419
+ */
420
+ interface SEOService {
421
+ /** Service configuration */
422
+ readonly config: SEOConfig;
423
+ /** Render metadata to HTML tags */
424
+ render(metadata: Metadata): RenderedHead;
425
+ /** Merge metadata (parent with child) */
426
+ merge(parent: Metadata, child: Metadata): Metadata;
427
+ /** Resolve title with template */
428
+ resolveTitle(metadata: Metadata): string;
429
+ /** Generate canonical URL */
430
+ canonical(path: string): string;
431
+ }
432
+
433
+ export type { AlternateLink as A, HtmlTag as H, IconMeta as I, Metadata as M, OpenGraphMeta as O, RenderedHead as R, SEOConfig as S, TwitterCardMeta as T, VerificationMeta as V, SEOService as a, ResolvedMetadata as b, RobotsMeta as c, OpenGraphType as d, OpenGraphImage as e, OpenGraphVideo as f, OpenGraphAudio as g, OpenGraphArticle as h, OpenGraphProfile as i, OpenGraphBook as j, OpenGraphProduct as k, TwitterCardType as l, TwitterCardImage as m, TwitterCardPlayer as n, TwitterCardApp as o };
@@ -0,0 +1,130 @@
1
+ import { Ref } from 'vue';
2
+ import { M as Metadata } from '../types-BBIMJIqz.js';
3
+ import { JsonLdSchema } from '../json-ld/index.js';
4
+
5
+ /**
6
+ * @flightdev/seo/vue
7
+ *
8
+ * Vue composables for SEO management.
9
+ * SSR-first with reactive client-side updates.
10
+ *
11
+ * @example
12
+ * ```vue
13
+ * <script setup>
14
+ * import { useSEO, useJsonLd } from '@flightdev/seo/vue';
15
+ *
16
+ * useSEO({
17
+ * title: 'My Page',
18
+ * description: 'Page description',
19
+ * });
20
+ *
21
+ * useJsonLd({
22
+ * '@type': 'WebPage',
23
+ * name: 'My Page',
24
+ * });
25
+ * </script>
26
+ * ```
27
+ */
28
+
29
+ interface SEOState {
30
+ metadata: Metadata;
31
+ setMetadata: (metadata: Metadata) => void;
32
+ addMetadata: (metadata: Metadata) => void;
33
+ }
34
+ /**
35
+ * Provide SEO context for the component tree
36
+ */
37
+ declare function provideSEO(defaultMetadata?: Metadata): SEOState;
38
+ /**
39
+ * Inject SEO context
40
+ */
41
+ declare function injectSEO(): SEOState | undefined;
42
+ interface UseSEOOptions {
43
+ immediate?: boolean;
44
+ }
45
+ /**
46
+ * Composable for managing page SEO metadata
47
+ *
48
+ * @example
49
+ * ```vue
50
+ * <script setup>
51
+ * import { useSEO } from '@flightdev/seo/vue';
52
+ *
53
+ * useSEO({
54
+ * title: 'Product Name',
55
+ * description: 'Product description',
56
+ * openGraph: {
57
+ * type: 'product',
58
+ * images: [{ url: '/product.jpg' }],
59
+ * },
60
+ * });
61
+ * </script>
62
+ * ```
63
+ */
64
+ declare function useSEO(metadata: Metadata | Ref<Metadata>, options?: UseSEOOptions): void;
65
+ interface SeoMetaInput {
66
+ title?: string;
67
+ titleTemplate?: string;
68
+ description?: string;
69
+ keywords?: string | string[];
70
+ author?: string;
71
+ robots?: string;
72
+ canonical?: string;
73
+ ogTitle?: string;
74
+ ogDescription?: string;
75
+ ogImage?: string;
76
+ ogUrl?: string;
77
+ ogType?: string;
78
+ ogSiteName?: string;
79
+ ogLocale?: string;
80
+ twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
81
+ twitterTitle?: string;
82
+ twitterDescription?: string;
83
+ twitterImage?: string;
84
+ twitterSite?: string;
85
+ twitterCreator?: string;
86
+ }
87
+ /**
88
+ * Flat SEO meta composable (similar to useSeoMeta from unhead)
89
+ *
90
+ * @example
91
+ * ```vue
92
+ * <script setup>
93
+ * import { useSeoMeta } from '@flightdev/seo/vue';
94
+ *
95
+ * useSeoMeta({
96
+ * title: 'Product Name',
97
+ * description: 'Product description',
98
+ * ogTitle: 'Product Name',
99
+ * ogImage: '/product.jpg',
100
+ * twitterCard: 'summary_large_image',
101
+ * });
102
+ * </script>
103
+ * ```
104
+ */
105
+ declare function useSeoMeta(input: SeoMetaInput | Ref<SeoMetaInput>): void;
106
+ /**
107
+ * Composable for JSON-LD structured data
108
+ *
109
+ * @example
110
+ * ```vue
111
+ * <script setup>
112
+ * import { useJsonLd } from '@flightdev/seo/vue';
113
+ *
114
+ * useJsonLd({
115
+ * '@type': 'Product',
116
+ * name: 'Widget',
117
+ * offers: { price: 9.99, priceCurrency: 'USD' },
118
+ * });
119
+ * </script>
120
+ * ```
121
+ */
122
+ declare function useJsonLd<T extends JsonLdSchema>(schema: T | Ref<T>, options?: {
123
+ id?: string;
124
+ }): void;
125
+ /**
126
+ * Render metadata to HTML string for SSR
127
+ */
128
+ declare function renderMetadataToString(metadata: Metadata): string;
129
+
130
+ export { type SEOState, type SeoMetaInput, type UseSEOOptions, injectSEO, provideSEO, renderMetadataToString, useJsonLd, useSEO, useSeoMeta };