@masters-ws/react-seo 1.4.0 → 1.4.1

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,1016 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ // src/core/utils.ts
28
+ function cleanSchema(obj) {
29
+ if (Array.isArray(obj)) {
30
+ return obj.filter((item) => item !== void 0 && item !== null).map((item) => typeof item === "object" ? cleanSchema(item) : item);
31
+ }
32
+ const cleaned = {};
33
+ for (const [key, value] of Object.entries(obj)) {
34
+ if (value === void 0 || value === null) continue;
35
+ if (Array.isArray(value)) {
36
+ const cleanedArr = value.filter((item) => item !== void 0 && item !== null).map((item) => typeof item === "object" && item !== null ? cleanSchema(item) : item);
37
+ if (cleanedArr.length > 0) {
38
+ cleaned[key] = cleanedArr;
39
+ }
40
+ } else if (typeof value === "object") {
41
+ cleaned[key] = cleanSchema(value);
42
+ } else {
43
+ cleaned[key] = value;
44
+ }
45
+ }
46
+ return cleaned;
47
+ }
48
+ function validateSEO(schemaType, data, requiredFields) {
49
+ const warnings = [];
50
+ for (const field of requiredFields) {
51
+ const value = data[field];
52
+ if (value === void 0 || value === null || value === "") {
53
+ warnings.push(`[react-seo] Warning: "${field}" is missing in ${schemaType} schema. Google may not show rich results.`);
54
+ }
55
+ }
56
+ if (warnings.length > 0 && typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
57
+ warnings.forEach((w) => console.warn(w));
58
+ }
59
+ return warnings;
60
+ }
61
+
62
+ // src/core/schemas.ts
63
+ function generateOrganizationSchema(config) {
64
+ return cleanSchema({
65
+ "@context": "https://schema.org",
66
+ "@type": "Organization",
67
+ "name": config.name,
68
+ "url": config.url,
69
+ "logo": config.logo,
70
+ "description": config.description,
71
+ "sameAs": config.socialLinks || []
72
+ });
73
+ }
74
+ function generateWebSiteSchema(config) {
75
+ return cleanSchema({
76
+ "@context": "https://schema.org",
77
+ "@type": "WebSite",
78
+ "name": config.name,
79
+ "url": config.url,
80
+ "description": config.description,
81
+ "publisher": {
82
+ "@type": "Organization",
83
+ "name": config.name,
84
+ "logo": config.logo
85
+ },
86
+ "potentialAction": {
87
+ "@type": "SearchAction",
88
+ "target": `${config.url}/search?q={search_term_string}`,
89
+ "query-input": "required name=search_term_string"
90
+ }
91
+ });
92
+ }
93
+ function generateWebPageSchema(data, config) {
94
+ return cleanSchema({
95
+ "@context": "https://schema.org",
96
+ "@type": "WebPage",
97
+ "name": data.name,
98
+ "description": data.description,
99
+ "url": data.url,
100
+ "image": data.image,
101
+ "datePublished": data.datePublished,
102
+ "dateModified": data.dateModified,
103
+ "isPartOf": {
104
+ "@type": "WebSite",
105
+ "name": config.name,
106
+ "url": config.url
107
+ },
108
+ "breadcrumb": data.breadcrumb ? generateBreadcrumbSchema(data.breadcrumb) : void 0
109
+ });
110
+ }
111
+ function generateCollectionPageSchema(data, config) {
112
+ return cleanSchema({
113
+ "@context": "https://schema.org",
114
+ "@type": "CollectionPage",
115
+ "name": data.name,
116
+ "description": data.description,
117
+ "url": data.url,
118
+ "image": data.image,
119
+ "numberOfItems": data.numberOfItems,
120
+ "isPartOf": {
121
+ "@type": "WebSite",
122
+ "name": config.name,
123
+ "url": config.url
124
+ }
125
+ });
126
+ }
127
+ function generateItemListSchema(data) {
128
+ return cleanSchema({
129
+ "@context": "https://schema.org",
130
+ "@type": "ItemList",
131
+ "name": data.name,
132
+ "url": data.url,
133
+ "itemListOrder": data.itemListOrder === "ascending" ? "https://schema.org/ItemListOrderAscending" : data.itemListOrder === "descending" ? "https://schema.org/ItemListOrderDescending" : "https://schema.org/ItemListUnordered",
134
+ "numberOfItems": data.items.length,
135
+ "itemListElement": data.items.map((item, index) => ({
136
+ "@type": "ListItem",
137
+ "position": item.position || index + 1,
138
+ "name": item.name,
139
+ "url": item.url,
140
+ "image": item.image
141
+ }))
142
+ });
143
+ }
144
+ function generateArticleSchema(data, config) {
145
+ validateSEO("NewsArticle", data, ["title", "description", "image", "publishedTime", "author"]);
146
+ const org = generateOrganizationSchema(config);
147
+ return cleanSchema({
148
+ "@context": "https://schema.org",
149
+ "@type": "NewsArticle",
150
+ "headline": data.title,
151
+ "description": data.description,
152
+ "image": data.image,
153
+ "datePublished": data.publishedTime,
154
+ "dateModified": data.modifiedTime || data.publishedTime,
155
+ "mainEntityOfPage": data.url,
156
+ "wordCount": data.wordCount,
157
+ "author": data.author ? {
158
+ "@type": "Person",
159
+ "name": data.author.name,
160
+ "url": data.author.url
161
+ } : org,
162
+ "publisher": org
163
+ });
164
+ }
165
+ function generateProductSchema(data) {
166
+ validateSEO("Product", data, ["name", "description", "image", "price"]);
167
+ let offers;
168
+ if (data.variants && data.variants.length > 0) {
169
+ const prices = data.variants.map((v) => v.price);
170
+ offers = {
171
+ "@type": "AggregateOffer",
172
+ "lowPrice": Math.min(...prices),
173
+ "highPrice": Math.max(...prices),
174
+ "priceCurrency": data.currency || data.variants[0]?.currency || "USD",
175
+ "offerCount": data.variants.length,
176
+ "offers": data.variants.map((v) => cleanSchema({
177
+ "@type": "Offer",
178
+ "name": v.name,
179
+ "sku": v.sku,
180
+ "price": v.price,
181
+ "priceCurrency": v.currency || data.currency || "USD",
182
+ "availability": v.availability || data.availability || "https://schema.org/InStock",
183
+ "url": v.url || data.url,
184
+ "image": v.image,
185
+ "itemCondition": data.condition ? `https://schema.org/${data.condition}` : void 0
186
+ }))
187
+ };
188
+ } else {
189
+ offers = cleanSchema({
190
+ "@type": "Offer",
191
+ "url": data.url,
192
+ "priceCurrency": data.currency || "USD",
193
+ "price": data.price,
194
+ "availability": data.availability || "https://schema.org/InStock",
195
+ "itemCondition": data.condition ? `https://schema.org/${data.condition}` : void 0,
196
+ "seller": data.seller ? {
197
+ "@type": "Organization",
198
+ "name": data.seller.name,
199
+ "url": data.seller.url
200
+ } : void 0,
201
+ "hasMerchantReturnPolicy": data.returnPolicy ? cleanSchema({
202
+ "@type": "MerchantReturnPolicy",
203
+ "applicableCountry": data.shipping?.shippingDestination,
204
+ "returnPolicyCategory": data.returnPolicy.returnPolicyCategory ? `https://schema.org/${data.returnPolicy.returnPolicyCategory}` : "https://schema.org/MerchantReturnFiniteReturnWindow",
205
+ "merchantReturnDays": data.returnPolicy.returnWithin,
206
+ "returnMethod": data.returnPolicy.returnMethod ? `https://schema.org/${data.returnPolicy.returnMethod}` : void 0,
207
+ "returnFees": data.returnPolicy.returnFees ? `https://schema.org/${data.returnPolicy.returnFees}` : void 0
208
+ }) : void 0,
209
+ "shippingDetails": data.shipping ? cleanSchema({
210
+ "@type": "OfferShippingDetails",
211
+ "shippingRate": data.shipping.shippingRate ? {
212
+ "@type": "MonetaryAmount",
213
+ "value": data.shipping.shippingRate.value,
214
+ "currency": data.shipping.shippingRate.currency
215
+ } : void 0,
216
+ "shippingDestination": data.shipping.shippingDestination ? {
217
+ "@type": "DefinedRegion",
218
+ "addressCountry": data.shipping.shippingDestination
219
+ } : void 0,
220
+ "deliveryTime": data.shipping.deliveryTime ? {
221
+ "@type": "ShippingDeliveryTime",
222
+ "handlingTime": {
223
+ "@type": "QuantitativeValue",
224
+ "minValue": 0,
225
+ "maxValue": 1,
226
+ "unitCode": "DAY"
227
+ },
228
+ "transitTime": {
229
+ "@type": "QuantitativeValue",
230
+ "minValue": data.shipping.deliveryTime.minDays,
231
+ "maxValue": data.shipping.deliveryTime.maxDays,
232
+ "unitCode": "DAY"
233
+ }
234
+ } : void 0,
235
+ "freeShippingThreshold": data.shipping.freeShippingThreshold ? {
236
+ "@type": "MonetaryAmount",
237
+ "value": data.shipping.freeShippingThreshold,
238
+ "currency": data.shipping.shippingRate?.currency || data.currency || "USD"
239
+ } : void 0
240
+ }) : void 0
241
+ });
242
+ }
243
+ const reviewList = data.reviews?.map((r) => cleanSchema({
244
+ "@type": "Review",
245
+ "author": { "@type": "Person", "name": r.author },
246
+ "datePublished": r.datePublished,
247
+ "reviewBody": r.reviewBody,
248
+ "reviewRating": {
249
+ "@type": "Rating",
250
+ "ratingValue": r.ratingValue,
251
+ "bestRating": r.bestRating || 5
252
+ }
253
+ }));
254
+ return cleanSchema({
255
+ "@context": "https://schema.org",
256
+ "@type": "Product",
257
+ "name": data.name,
258
+ "description": data.description,
259
+ "image": data.image,
260
+ "sku": data.sku,
261
+ "gtin": data.gtin,
262
+ "mpn": data.mpn,
263
+ "brand": data.brand ? { "@type": "Brand", "name": data.brand } : void 0,
264
+ "offers": offers,
265
+ "aggregateRating": data.rating ? {
266
+ "@type": "AggregateRating",
267
+ "ratingValue": data.rating,
268
+ "reviewCount": data.reviewCount || 1
269
+ } : void 0,
270
+ "review": reviewList && reviewList.length > 0 ? reviewList : void 0
271
+ });
272
+ }
273
+ function generateFAQSchema(questions) {
274
+ return cleanSchema({
275
+ "@context": "https://schema.org",
276
+ "@type": "FAQPage",
277
+ "mainEntity": questions.map((item) => ({
278
+ "@type": "Question",
279
+ "name": item.q,
280
+ "acceptedAnswer": {
281
+ "@type": "Answer",
282
+ "text": item.a
283
+ }
284
+ }))
285
+ });
286
+ }
287
+ function generateBreadcrumbSchema(items) {
288
+ return cleanSchema({
289
+ "@context": "https://schema.org",
290
+ "@type": "BreadcrumbList",
291
+ "itemListElement": items.map((item, index) => ({
292
+ "@type": "ListItem",
293
+ "position": index + 1,
294
+ "name": item.name,
295
+ "item": item.item
296
+ }))
297
+ });
298
+ }
299
+ function generateVideoSchema(data) {
300
+ validateSEO("VideoObject", data, ["name", "description", "thumbnailUrl", "uploadDate"]);
301
+ return cleanSchema({
302
+ "@context": "https://schema.org",
303
+ "@type": "VideoObject",
304
+ "name": data.name,
305
+ "description": data.description,
306
+ "thumbnailUrl": data.thumbnailUrl,
307
+ "uploadDate": data.uploadDate,
308
+ "duration": data.duration,
309
+ "contentUrl": data.contentUrl,
310
+ "embedUrl": data.embedUrl
311
+ });
312
+ }
313
+ function generateEventSchema(data) {
314
+ const isOnline = data.location && "url" in data.location;
315
+ return cleanSchema({
316
+ "@context": "https://schema.org",
317
+ "@type": "Event",
318
+ "name": data.name,
319
+ "description": data.description,
320
+ "startDate": data.startDate,
321
+ "endDate": data.endDate,
322
+ "eventAttendanceMode": isOnline ? "https://schema.org/OnlineEventAttendanceMode" : "https://schema.org/OfflineEventAttendanceMode",
323
+ "location": isOnline ? {
324
+ "@type": "VirtualLocation",
325
+ "url": data.location.url
326
+ } : data.location ? {
327
+ "@type": "Place",
328
+ "name": data.location.name,
329
+ "address": data.location.address
330
+ } : void 0,
331
+ "image": data.image,
332
+ "offers": data.offers ? {
333
+ "@type": "Offer",
334
+ "price": data.offers.price,
335
+ "priceCurrency": data.offers.currency,
336
+ "url": data.offers.url
337
+ } : void 0
338
+ });
339
+ }
340
+ function generateLocalBusinessSchema(data) {
341
+ return cleanSchema({
342
+ "@context": "https://schema.org",
343
+ "@type": "LocalBusiness",
344
+ "name": data.name,
345
+ "description": data.description,
346
+ "image": data.image,
347
+ "telephone": data.telephone,
348
+ "address": {
349
+ "@type": "PostalAddress",
350
+ "streetAddress": data.address.street,
351
+ "addressLocality": data.address.city,
352
+ "addressRegion": data.address.region,
353
+ "postalCode": data.address.postalCode,
354
+ "addressCountry": data.address.country
355
+ },
356
+ "geo": data.geo ? {
357
+ "@type": "GeoCoordinates",
358
+ "latitude": data.geo.lat,
359
+ "longitude": data.geo.lng
360
+ } : void 0,
361
+ "openingHours": data.openingHours,
362
+ "priceRange": data.priceRange
363
+ });
364
+ }
365
+ function generateSoftwareSchema(data) {
366
+ return cleanSchema({
367
+ "@context": "https://schema.org",
368
+ "@type": "SoftwareApplication",
369
+ "name": data.name,
370
+ "description": data.description,
371
+ "operatingSystem": data.operatingSystem,
372
+ "applicationCategory": data.applicationCategory,
373
+ "offers": data.offers ? {
374
+ "@type": "Offer",
375
+ "price": data.offers.price,
376
+ "priceCurrency": data.offers.currency
377
+ } : void 0,
378
+ "aggregateRating": data.rating ? {
379
+ "@type": "AggregateRating",
380
+ "ratingValue": data.rating,
381
+ "reviewCount": data.reviewCount || 1
382
+ } : void 0,
383
+ "downloadUrl": data.downloadUrl,
384
+ "screenshot": data.screenshot
385
+ });
386
+ }
387
+ function generateBookSchema(data) {
388
+ return cleanSchema({
389
+ "@context": "https://schema.org",
390
+ "@type": "Book",
391
+ "name": data.name,
392
+ "author": typeof data.author === "string" ? {
393
+ "@type": "Person",
394
+ "name": data.author
395
+ } : {
396
+ "@type": "Person",
397
+ "name": data.author.name,
398
+ "url": data.author.url
399
+ },
400
+ "description": data.description,
401
+ "isbn": data.isbn,
402
+ "numberOfPages": data.numberOfPages,
403
+ "publisher": data.publisher ? {
404
+ "@type": "Organization",
405
+ "name": data.publisher
406
+ } : void 0,
407
+ "datePublished": data.datePublished,
408
+ "image": data.image,
409
+ "inLanguage": data.inLanguage,
410
+ "genre": data.genre
411
+ });
412
+ }
413
+ function generateMovieSchema(data) {
414
+ return cleanSchema({
415
+ "@context": "https://schema.org",
416
+ "@type": "Movie",
417
+ "name": data.name,
418
+ "description": data.description,
419
+ "image": data.image,
420
+ "director": data.director ? {
421
+ "@type": "Person",
422
+ "name": data.director
423
+ } : void 0,
424
+ "actor": data.actor?.map((name) => ({
425
+ "@type": "Person",
426
+ "name": name
427
+ })),
428
+ "dateCreated": data.dateCreated,
429
+ "duration": data.duration,
430
+ "genre": data.genre,
431
+ "aggregateRating": data.rating ? {
432
+ "@type": "AggregateRating",
433
+ "ratingValue": data.rating,
434
+ "reviewCount": data.reviewCount || 1
435
+ } : void 0
436
+ });
437
+ }
438
+ function generatePodcastSchema(data) {
439
+ return cleanSchema({
440
+ "@context": "https://schema.org",
441
+ "@type": "PodcastSeries",
442
+ "name": data.name,
443
+ "description": data.description,
444
+ "image": data.image,
445
+ "author": data.author ? {
446
+ "@type": "Person",
447
+ "name": data.author
448
+ } : void 0,
449
+ "webFeed": data.webFeed,
450
+ "url": data.url,
451
+ "genre": data.genre
452
+ });
453
+ }
454
+ function generatePodcastEpisodeSchema(data) {
455
+ return cleanSchema({
456
+ "@context": "https://schema.org",
457
+ "@type": "PodcastEpisode",
458
+ "name": data.name,
459
+ "description": data.description,
460
+ "datePublished": data.datePublished,
461
+ "timeRequired": data.duration,
462
+ "url": data.url,
463
+ "associatedMedia": data.audio ? {
464
+ "@type": "AudioObject",
465
+ "contentUrl": data.audio
466
+ } : void 0,
467
+ "partOfSeries": data.partOfSeries ? {
468
+ "@type": "PodcastSeries",
469
+ "name": data.partOfSeries.name,
470
+ "url": data.partOfSeries.url
471
+ } : void 0
472
+ });
473
+ }
474
+ function generateHowToSchema(data) {
475
+ return cleanSchema({
476
+ "@context": "https://schema.org",
477
+ "@type": "HowTo",
478
+ "name": data.name,
479
+ "description": data.description,
480
+ "image": data.image,
481
+ "totalTime": data.totalTime,
482
+ "estimatedCost": data.estimatedCost ? {
483
+ "@type": "MonetaryAmount",
484
+ "currency": data.estimatedCost.currency,
485
+ "value": data.estimatedCost.value
486
+ } : void 0,
487
+ "supply": data.supply?.map((s) => ({ "@type": "HowToSupply", "name": s })),
488
+ "tool": data.tool?.map((t) => ({ "@type": "HowToTool", "name": t })),
489
+ "step": data.steps.map((step, index) => {
490
+ if (typeof step === "string") {
491
+ return { "@type": "HowToStep", "position": index + 1, "text": step };
492
+ }
493
+ return cleanSchema({
494
+ "@type": "HowToStep",
495
+ "position": index + 1,
496
+ "name": step.name,
497
+ "text": step.text,
498
+ "image": step.image,
499
+ "url": step.url
500
+ });
501
+ })
502
+ });
503
+ }
504
+ function generateRecipeSchema(data) {
505
+ return cleanSchema({
506
+ "@context": "https://schema.org",
507
+ "@type": "Recipe",
508
+ "name": data.name,
509
+ "description": data.description,
510
+ "image": data.image,
511
+ "author": { "@type": "Person", "name": data.author },
512
+ "datePublished": data.publishedDate,
513
+ "prepTime": data.prepTime,
514
+ "cookTime": data.cookTime,
515
+ "totalTime": data.totalTime,
516
+ "recipeYield": data.recipeYield,
517
+ "recipeCategory": data.recipeCategory,
518
+ "recipeCuisine": data.recipeCuisine,
519
+ "recipeIngredient": data.ingredients,
520
+ "recipeInstructions": data.instructions.map((step) => cleanSchema({
521
+ "@type": "HowToStep",
522
+ "name": step.name,
523
+ "text": step.text,
524
+ "image": step.image
525
+ })),
526
+ "aggregateRating": data.rating ? {
527
+ "@type": "AggregateRating",
528
+ "ratingValue": data.rating,
529
+ "reviewCount": data.reviewCount || 1
530
+ } : void 0
531
+ });
532
+ }
533
+ function generateJobPostingSchema(data) {
534
+ return cleanSchema({
535
+ "@context": "https://schema.org",
536
+ "@type": "JobPosting",
537
+ "title": data.title,
538
+ "description": data.description,
539
+ "datePosted": data.datePosted,
540
+ "validThrough": data.validThrough,
541
+ "employmentType": data.employmentType,
542
+ "jobLocationType": data.remote ? "TELECOMMUTE" : void 0,
543
+ "hiringOrganization": {
544
+ "@type": "Organization",
545
+ "name": data.hiringOrganization.name,
546
+ "sameAs": data.hiringOrganization.sameAs,
547
+ "logo": data.hiringOrganization.logo
548
+ },
549
+ "jobLocation": {
550
+ "@type": "Place",
551
+ "address": {
552
+ "@type": "PostalAddress",
553
+ "streetAddress": data.jobLocation.streetAddress,
554
+ "addressLocality": data.jobLocation.addressLocality,
555
+ "addressRegion": data.jobLocation.addressRegion,
556
+ "postalCode": data.jobLocation.postalCode,
557
+ "addressCountry": data.jobLocation.addressCountry
558
+ }
559
+ },
560
+ "baseSalary": data.baseSalary ? {
561
+ "@type": "MonetaryAmount",
562
+ "currency": data.baseSalary.currency,
563
+ "value": typeof data.baseSalary.value === "number" ? {
564
+ "@type": "QuantitativeValue",
565
+ "value": data.baseSalary.value,
566
+ "unitText": data.baseSalary.unitText || "MONTH"
567
+ } : {
568
+ "@type": "QuantitativeValue",
569
+ "minValue": data.baseSalary.value.minValue,
570
+ "maxValue": data.baseSalary.value.maxValue,
571
+ "unitText": data.baseSalary.unitText || "MONTH"
572
+ }
573
+ } : void 0
574
+ });
575
+ }
576
+
577
+ // src/core/metadata.ts
578
+ function toNextMetadata(props, config) {
579
+ const title = props.title ? `${props.title} | ${config.name}` : config.name;
580
+ const description = props.description || config.description;
581
+ const url = props.canonical || config.url;
582
+ const image = props.image || config.logo;
583
+ const metadata = {
584
+ title,
585
+ description,
586
+ keywords: props.keywords,
587
+ robots: props.noindex ? "noindex, nofollow" : props.robots || "index, follow",
588
+ alternates: {
589
+ canonical: props.noindex ? void 0 : url
590
+ },
591
+ openGraph: {
592
+ title: props.ogTitle || title,
593
+ description: props.ogDescription || description,
594
+ url,
595
+ siteName: config.name,
596
+ images: props.ogImage || image ? [{
597
+ url: props.ogImage || image,
598
+ width: props.ogImageWidth || 1200,
599
+ height: props.ogImageHeight || 630,
600
+ alt: props.ogImageAlt || title
601
+ }] : [],
602
+ type: props.ogType || (props.type === "article" ? "article" : "website"),
603
+ locale: props.ogLocale || config.language || "ar_SA"
604
+ },
605
+ twitter: {
606
+ card: props.twitterCard || "summary_large_image",
607
+ title: props.twitterTitle || title,
608
+ description: props.twitterDescription || description,
609
+ images: props.twitterImage || image ? [{
610
+ url: props.twitterImage || image,
611
+ alt: props.twitterImageAlt || title
612
+ }] : [],
613
+ site: config.twitterHandle,
614
+ creator: config.twitterHandle
615
+ },
616
+ other: {}
617
+ };
618
+ if (config.facebookAppId) {
619
+ metadata.other["fb:app_id"] = config.facebookAppId;
620
+ }
621
+ if (props.alternates && props.alternates.length > 0) {
622
+ const languages = {};
623
+ props.alternates.forEach((alt) => {
624
+ languages[alt.hreflang] = alt.href;
625
+ });
626
+ metadata.alternates.languages = languages;
627
+ }
628
+ if (props.prev) {
629
+ metadata.alternates.prev = props.prev;
630
+ }
631
+ if (props.next) {
632
+ metadata.alternates.next = props.next;
633
+ }
634
+ metadata.appleWebApp = {
635
+ capable: true,
636
+ title: config.name,
637
+ statusBarStyle: "default"
638
+ };
639
+ if (config.themeColor) metadata.themeColor = config.themeColor;
640
+ if (config.manifest) metadata.manifest = config.manifest;
641
+ if (props.type === "article") {
642
+ if (props.publishedTime) {
643
+ metadata.openGraph.publishedTime = props.publishedTime;
644
+ }
645
+ if (props.modifiedTime) {
646
+ metadata.openGraph.modifiedTime = props.modifiedTime;
647
+ }
648
+ if (props.author) {
649
+ metadata.openGraph.authors = [props.author.name];
650
+ }
651
+ if (props.section) {
652
+ metadata.openGraph.section = props.section;
653
+ }
654
+ if (props.tags?.length) {
655
+ metadata.openGraph.tags = props.tags;
656
+ }
657
+ }
658
+ if (props.type === "product" && props.product) {
659
+ if (props.product.price !== void 0 && props.product.currency) {
660
+ metadata.other["product:price:amount"] = props.product.price.toString();
661
+ metadata.other["product:price:currency"] = props.product.currency;
662
+ }
663
+ if (props.product.availability) {
664
+ metadata.other["product:availability"] = props.product.availability;
665
+ }
666
+ if (props.product.brand) {
667
+ metadata.other["product:brand"] = props.product.brand;
668
+ }
669
+ }
670
+ if (props.readingTime) {
671
+ metadata.other["twitter:label1"] = "Reading time";
672
+ metadata.other["twitter:data1"] = `${props.readingTime} min`;
673
+ }
674
+ if (props.whatsappImage) {
675
+ metadata.other["og:image:secure_url"] = props.whatsappImage;
676
+ }
677
+ if (Object.keys(metadata.other).length === 0) {
678
+ delete metadata.other;
679
+ }
680
+ return metadata;
681
+ }
682
+ function generatePaginationLinks(baseUrl, currentPage, totalPages) {
683
+ const hasNext = currentPage < totalPages;
684
+ const hasPrev = currentPage > 1;
685
+ const cleanBase = baseUrl.split("?")[0];
686
+ return {
687
+ next: hasNext ? `${cleanBase}?page=${currentPage + 1}` : void 0,
688
+ prev: hasPrev ? currentPage === 2 ? cleanBase : `${cleanBase}?page=${currentPage - 1}` : void 0,
689
+ canonical: currentPage === 1 ? cleanBase : `${cleanBase}?page=${currentPage}`
690
+ };
691
+ }
692
+ function generatePaginatedTitle(title, page, suffix = "Page") {
693
+ return page > 1 ? `${title} - ${suffix} ${page}` : title;
694
+ }
695
+
696
+ // src/core/JsonLd.tsx
697
+ import { Fragment, jsx } from "react/jsx-runtime";
698
+ function JsonLd({ schema, graph = false }) {
699
+ const schemas = Array.isArray(schema) ? schema : [schema];
700
+ if (graph && schemas.length > 1) {
701
+ const graphData = {
702
+ "@context": "https://schema.org",
703
+ "@graph": schemas.map((s) => {
704
+ const { "@context": _, ...rest } = s;
705
+ return rest;
706
+ })
707
+ };
708
+ return /* @__PURE__ */ jsx(
709
+ "script",
710
+ {
711
+ type: "application/ld+json",
712
+ dangerouslySetInnerHTML: { __html: JSON.stringify(graphData) }
713
+ }
714
+ );
715
+ }
716
+ return /* @__PURE__ */ jsx(Fragment, { children: schemas.map((s, i) => /* @__PURE__ */ jsx(
717
+ "script",
718
+ {
719
+ type: "application/ld+json",
720
+ dangerouslySetInnerHTML: { __html: JSON.stringify(s) }
721
+ },
722
+ i
723
+ )) });
724
+ }
725
+
726
+ // src/core/product-metadata.ts
727
+ function generateProductMetadata(product, config) {
728
+ const primaryImage = Array.isArray(product.image) ? product.image[0] : product.image;
729
+ const seoData = {
730
+ title: product.metaTitle || product.name,
731
+ description: product.metaDescription || product.description,
732
+ image: product.ogImage || primaryImage,
733
+ canonical: product.canonical || product.url,
734
+ type: "product",
735
+ noindex: product.noindex,
736
+ ogTitle: product.name,
737
+ ogDescription: product.description,
738
+ ogImage: product.ogImage || primaryImage,
739
+ ogImageWidth: product.ogImageWidth || 1200,
740
+ ogImageHeight: product.ogImageHeight || 630,
741
+ ogType: "product",
742
+ product: {
743
+ sku: product.sku,
744
+ brand: product.brand,
745
+ price: product.price,
746
+ currency: product.currency,
747
+ availability: product.availability,
748
+ rating: product.rating,
749
+ reviewCount: product.reviewCount
750
+ }
751
+ };
752
+ const metadata = toNextMetadata(seoData, config);
753
+ if (product.price !== void 0 && product.currency) {
754
+ metadata.other = {
755
+ ...metadata.other,
756
+ "product:price:amount": product.price.toString(),
757
+ "product:price:currency": product.currency
758
+ };
759
+ if (product.availability) {
760
+ metadata.other["product:availability"] = product.availability;
761
+ }
762
+ if (product.brand) {
763
+ metadata.other["product:brand"] = product.brand;
764
+ }
765
+ if (product.condition) {
766
+ metadata.other["product:condition"] = product.condition;
767
+ }
768
+ }
769
+ const productSchema = generateProductSchema({
770
+ name: product.name,
771
+ description: product.description,
772
+ image: product.image,
773
+ sku: product.sku,
774
+ gtin: product.gtin,
775
+ mpn: product.mpn,
776
+ brand: product.brand,
777
+ price: product.price,
778
+ currency: product.currency,
779
+ availability: product.availability,
780
+ rating: product.rating,
781
+ reviewCount: product.reviewCount,
782
+ url: product.url,
783
+ condition: product.condition,
784
+ reviews: product.reviews,
785
+ returnPolicy: product.returnPolicy,
786
+ shipping: product.shipping,
787
+ variants: product.variants,
788
+ seller: product.seller
789
+ });
790
+ const breadcrumbItems = product.breadcrumbs || [
791
+ { name: "Home", item: config.url },
792
+ { name: "Shop", item: `${config.url}/shop` },
793
+ ...product.category ? [{ name: product.category, item: `${config.url}/categories/${encodeURIComponent(product.category)}` }] : [],
794
+ { name: product.name, item: product.url }
795
+ ];
796
+ const breadcrumbSchema = generateBreadcrumbSchema(breadcrumbItems);
797
+ const organizationSchema = generateOrganizationSchema(config);
798
+ const websiteSchema = generateWebSiteSchema(config);
799
+ return {
800
+ metadata,
801
+ schemas: [productSchema, breadcrumbSchema, organizationSchema, websiteSchema],
802
+ productSchema,
803
+ breadcrumbSchema,
804
+ organizationSchema,
805
+ websiteSchema
806
+ };
807
+ }
808
+
809
+ // src/core/article-metadata.ts
810
+ function generateArticleMetadata(article, config) {
811
+ const primaryImage = Array.isArray(article.image) ? article.image[0] : article.image;
812
+ const seoData = {
813
+ title: article.metaTitle || article.title,
814
+ description: article.metaDescription || article.description,
815
+ image: article.ogImage || primaryImage,
816
+ canonical: article.canonical || article.url,
817
+ type: "article",
818
+ noindex: article.noindex,
819
+ publishedTime: article.publishedTime,
820
+ modifiedTime: article.modifiedTime,
821
+ author: article.author,
822
+ section: article.category,
823
+ tags: article.tags,
824
+ readingTime: article.readingTime,
825
+ ogTitle: article.title,
826
+ ogDescription: article.description,
827
+ ogImage: article.ogImage || primaryImage,
828
+ ogImageWidth: article.ogImageWidth || 1200,
829
+ ogImageHeight: article.ogImageHeight || 630,
830
+ ogType: "article"
831
+ };
832
+ const metadata = toNextMetadata(seoData, config);
833
+ if (article.publishedTime) {
834
+ metadata.other = {
835
+ ...metadata.other,
836
+ "article:published_time": article.publishedTime
837
+ };
838
+ }
839
+ if (article.modifiedTime) {
840
+ metadata.other = {
841
+ ...metadata.other,
842
+ "article:modified_time": article.modifiedTime
843
+ };
844
+ }
845
+ if (article.category) {
846
+ metadata.other = {
847
+ ...metadata.other,
848
+ "article:section": article.category
849
+ };
850
+ }
851
+ if (article.tags?.length) {
852
+ metadata.other = {
853
+ ...metadata.other,
854
+ "article:tag": article.tags.join(",")
855
+ };
856
+ }
857
+ const articleSchema = generateArticleSchema({
858
+ title: article.title,
859
+ description: article.description,
860
+ image: article.image,
861
+ publishedTime: article.publishedTime,
862
+ modifiedTime: article.modifiedTime,
863
+ author: article.author,
864
+ url: article.url,
865
+ wordCount: article.wordCount
866
+ }, config);
867
+ const breadcrumbItems = article.breadcrumbs || [
868
+ { name: "Home", item: config.url },
869
+ ...article.category ? [{ name: article.category, item: `${config.url}/category/${encodeURIComponent(article.category)}` }] : [],
870
+ { name: article.title, item: article.url }
871
+ ];
872
+ const breadcrumbSchema = generateBreadcrumbSchema(breadcrumbItems);
873
+ const organizationSchema = generateOrganizationSchema(config);
874
+ const websiteSchema = generateWebSiteSchema(config);
875
+ return {
876
+ metadata,
877
+ schemas: [articleSchema, breadcrumbSchema, organizationSchema, websiteSchema],
878
+ articleSchema,
879
+ breadcrumbSchema,
880
+ organizationSchema,
881
+ websiteSchema
882
+ };
883
+ }
884
+
885
+ // src/core/category-metadata.ts
886
+ function generateCategoryMetadata(category, config) {
887
+ const page = category.page || 1;
888
+ const totalPages = category.totalPages || 1;
889
+ const pageSuffix = category.pageSuffix || "Page";
890
+ const pagination = generatePaginationLinks(category.url, page, totalPages);
891
+ const title = generatePaginatedTitle(
892
+ category.metaTitle || category.name,
893
+ page,
894
+ pageSuffix
895
+ );
896
+ const seoData = {
897
+ title,
898
+ description: category.metaDescription || category.description,
899
+ image: category.image,
900
+ canonical: pagination.canonical,
901
+ type: "website",
902
+ noindex: category.noindex,
903
+ prev: pagination.prev,
904
+ next: pagination.next
905
+ };
906
+ const metadata = toNextMetadata(seoData, config);
907
+ const collectionPageSchema = generateCollectionPageSchema({
908
+ name: category.name,
909
+ description: category.description,
910
+ url: pagination.canonical || category.url,
911
+ image: category.image,
912
+ numberOfItems: category.items?.length
913
+ }, config);
914
+ const breadcrumbItems = category.breadcrumbs || [
915
+ { name: "Home", item: config.url },
916
+ ...category.parentCategory ? [{ name: category.parentCategory, item: `${config.url}/categories` }] : [],
917
+ { name: category.name, item: category.url }
918
+ ];
919
+ const breadcrumbSchema = generateBreadcrumbSchema(breadcrumbItems);
920
+ const organizationSchema = generateOrganizationSchema(config);
921
+ let itemListSchema;
922
+ if (category.items && category.items.length > 0) {
923
+ itemListSchema = generateItemListSchema({
924
+ name: category.name,
925
+ url: pagination.canonical || category.url,
926
+ items: category.items
927
+ });
928
+ }
929
+ const schemas = [collectionPageSchema, breadcrumbSchema, organizationSchema];
930
+ if (itemListSchema) schemas.push(itemListSchema);
931
+ return {
932
+ metadata,
933
+ schemas,
934
+ collectionPageSchema,
935
+ breadcrumbSchema,
936
+ organizationSchema,
937
+ itemListSchema
938
+ };
939
+ }
940
+
941
+ // src/core/homepage-metadata.ts
942
+ function generateHomepageMetadata(input, config) {
943
+ const seoData = {
944
+ title: input.title || config.name,
945
+ description: input.description || config.description,
946
+ image: input.ogImage || input.image || config.logo,
947
+ canonical: input.canonical || config.url,
948
+ type: "website",
949
+ ogTitle: input.title || config.name,
950
+ ogDescription: input.description || config.description,
951
+ ogImage: input.ogImage || input.image || config.logo,
952
+ ogImageWidth: input.ogImageWidth || 1200,
953
+ ogImageHeight: input.ogImageHeight || 630
954
+ };
955
+ const metadata = toNextMetadata(seoData, config);
956
+ const webPageSchema = generateWebPageSchema({
957
+ name: input.title || config.name,
958
+ description: input.description || config.description,
959
+ url: config.url,
960
+ image: input.image || config.logo
961
+ }, config);
962
+ const organizationSchema = generateOrganizationSchema({
963
+ ...config,
964
+ socialLinks: input.socialLinks || config.socialLinks
965
+ });
966
+ const websiteSchema = generateWebSiteSchema(config);
967
+ const schemas = [webPageSchema, organizationSchema, websiteSchema];
968
+ let localBusinessSchema;
969
+ if (input.localBusiness) {
970
+ localBusinessSchema = generateLocalBusinessSchema(input.localBusiness);
971
+ schemas.push(localBusinessSchema);
972
+ }
973
+ return {
974
+ metadata,
975
+ schemas,
976
+ webPageSchema,
977
+ organizationSchema,
978
+ websiteSchema,
979
+ localBusinessSchema
980
+ };
981
+ }
982
+
983
+ export {
984
+ __commonJS,
985
+ __toESM,
986
+ cleanSchema,
987
+ validateSEO,
988
+ generateOrganizationSchema,
989
+ generateWebSiteSchema,
990
+ generateWebPageSchema,
991
+ generateCollectionPageSchema,
992
+ generateItemListSchema,
993
+ generateArticleSchema,
994
+ generateProductSchema,
995
+ generateFAQSchema,
996
+ generateBreadcrumbSchema,
997
+ generateVideoSchema,
998
+ generateEventSchema,
999
+ generateLocalBusinessSchema,
1000
+ generateSoftwareSchema,
1001
+ generateBookSchema,
1002
+ generateMovieSchema,
1003
+ generatePodcastSchema,
1004
+ generatePodcastEpisodeSchema,
1005
+ generateHowToSchema,
1006
+ generateRecipeSchema,
1007
+ generateJobPostingSchema,
1008
+ toNextMetadata,
1009
+ generatePaginationLinks,
1010
+ generatePaginatedTitle,
1011
+ JsonLd,
1012
+ generateProductMetadata,
1013
+ generateArticleMetadata,
1014
+ generateCategoryMetadata,
1015
+ generateHomepageMetadata
1016
+ };