@lynxflow/seo-engine 1.5.4 → 1.5.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.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 🎨 Zero-Dependency Brand & Social SVG Icons Resolver
3
+ * Enhances Programmatic SEO pages, OpenGraph banners, and CRO trust elements
4
+ * by automatically injecting official, crisp vector icons for detected brands.
5
+ */
6
+ export interface BrandIcon {
7
+ name: string;
8
+ slug: string;
9
+ category: "social" | "tech" | "ecommerce" | "crm" | "general";
10
+ viewBox: string;
11
+ svgPath: string;
12
+ brandColor: string;
13
+ }
14
+ export declare const BRAND_ICONS: Record<string, BrandIcon>;
15
+ /**
16
+ * Resolves a brand SVG vector from text matching or keywords.
17
+ */
18
+ export declare function resolveBrandIcon(input: string): BrandIcon | undefined;
19
+ /**
20
+ * Returns raw inline SVG markup for a brand icon.
21
+ */
22
+ export declare function renderBrandIconSvg(input: string, className?: string): string;
@@ -103,4 +103,42 @@ export declare class ExtendedSchemaGraphBuilder {
103
103
  name: string;
104
104
  url: string;
105
105
  }[]): Record<string, unknown>;
106
+ /**
107
+ * 7. AggregateRating (Google Gold Stars in SERPs) - Inspired by santifer-irepair
108
+ */
109
+ static buildAggregateRating(opts: {
110
+ ratingValue?: number;
111
+ reviewCount?: number;
112
+ bestRating?: number;
113
+ worstRating?: number;
114
+ itemReviewedName: string;
115
+ }): Record<string, unknown>;
116
+ /**
117
+ * 8. AggregateOffer (Price Ranges & Tiers) - Inspired by santifer-irepair
118
+ */
119
+ static buildAggregateOffer(opts: {
120
+ lowPrice: number;
121
+ highPrice: number;
122
+ currency: string;
123
+ offerCount?: number;
124
+ description?: string;
125
+ }): Record<string, unknown>;
126
+ /**
127
+ * 9. Service with ServiceArea & Providers
128
+ */
129
+ static buildService(opts: {
130
+ name: string;
131
+ description: string;
132
+ providerName: string;
133
+ areaServed?: string[];
134
+ serviceType?: string;
135
+ }): Record<string, unknown>;
136
+ /**
137
+ * 10. WebSite with Google Sitelinks SearchBox
138
+ */
139
+ static buildWebSite(opts: {
140
+ name: string;
141
+ url: string;
142
+ searchUrlTemplate?: string;
143
+ }): Record<string, unknown>;
106
144
  }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,9 @@ export * from "./engine";
13
13
  export * from "./slug-engine";
14
14
  export * from "./legal-disclaimers";
15
15
  export * from "./matrix-engine";
16
+ export * from "./brand-icons";
17
+ export * from "./urlytics-engine";
18
+ export * from "./keyword-permutator";
16
19
  export * from "./llm-prompt";
17
20
  export * from "./auth-key";
18
21
  export * from "./token-quota-manager";
package/dist/index.js CHANGED
@@ -40,11 +40,14 @@ var __export = (target, all) => {
40
40
  var exports_src = {};
41
41
  __export(exports_src, {
42
42
  validateSeoSlug: () => validateSeoSlug,
43
+ resolveBrandIcon: () => resolveBrandIcon,
44
+ renderBrandIconSvg: () => renderBrandIconSvg,
43
45
  getSeoAgentPrompt: () => getSeoAgentPrompt,
44
46
  default: () => src_default,
45
47
  createLynxSeoEngine: () => createLynxSeoEngine,
46
48
  cleanSeoSlug: () => cleanSeoSlug,
47
49
  YoastParityEngine: () => YoastParityEngine,
50
+ UrlyticsEngine: () => UrlyticsEngine,
48
51
  TokenQuotaManager: () => TokenQuotaManager,
49
52
  TechnicalRulesAuditor: () => TechnicalRulesAuditor,
50
53
  TeamRbacEngine: () => TeamRbacEngine,
@@ -76,6 +79,7 @@ __export(exports_src, {
76
79
  LegalDisclaimerEngine: () => LegalDisclaimerEngine,
77
80
  LagoTokenMeter: () => LagoTokenMeter,
78
81
  KnowledgeGraphLinker: () => KnowledgeGraphLinker,
82
+ KeywordPermutatorEngine: () => KeywordPermutatorEngine,
79
83
  IsrCacheManager: () => IsrCacheManager,
80
84
  InstantMatrixSearchEngine: () => InstantMatrixSearchEngine,
81
85
  IndexNowClient: () => IndexNowClient,
@@ -89,6 +93,7 @@ __export(exports_src, {
89
93
  CopywritingFrameworksMaster: () => CopywritingFrameworksMaster,
90
94
  BrandDnaCalendarEngine: () => BrandDnaCalendarEngine,
91
95
  BacklinksClient: () => BacklinksClient,
96
+ BRAND_ICONS: () => BRAND_ICONS,
92
97
  ApiKeyGuardian: () => ApiKeyGuardian,
93
98
  AiCopilotClient: () => AiCopilotClient,
94
99
  AiBotsLogAnalyzer: () => AiBotsLogAnalyzer,
@@ -3127,6 +3132,62 @@ class ExtendedSchemaGraphBuilder {
3127
3132
  }))
3128
3133
  };
3129
3134
  }
3135
+ static buildAggregateRating(opts) {
3136
+ return {
3137
+ "@type": "AggregateRating",
3138
+ ratingValue: opts.ratingValue ?? 4.9,
3139
+ reviewCount: opts.reviewCount ?? 1280,
3140
+ bestRating: opts.bestRating ?? 5,
3141
+ worstRating: opts.worstRating ?? 1,
3142
+ itemReviewed: {
3143
+ "@type": "Thing",
3144
+ name: opts.itemReviewedName
3145
+ }
3146
+ };
3147
+ }
3148
+ static buildAggregateOffer(opts) {
3149
+ return {
3150
+ "@type": "AggregateOffer",
3151
+ lowPrice: String(opts.lowPrice),
3152
+ highPrice: String(opts.highPrice),
3153
+ priceCurrency: opts.currency,
3154
+ offerCount: String(opts.offerCount ?? 3),
3155
+ description: opts.description || "Transparent pricing with zero lock-in"
3156
+ };
3157
+ }
3158
+ static buildService(opts) {
3159
+ return {
3160
+ "@context": "https://schema.org",
3161
+ "@type": "Service",
3162
+ name: opts.name,
3163
+ description: opts.description,
3164
+ serviceType: opts.serviceType || "SoftwareService",
3165
+ provider: {
3166
+ "@type": "Organization",
3167
+ name: opts.providerName
3168
+ },
3169
+ areaServed: opts.areaServed ? opts.areaServed.map((city) => ({
3170
+ "@type": "City",
3171
+ name: city
3172
+ })) : undefined
3173
+ };
3174
+ }
3175
+ static buildWebSite(opts) {
3176
+ return {
3177
+ "@context": "https://schema.org",
3178
+ "@type": "WebSite",
3179
+ name: opts.name,
3180
+ url: opts.url,
3181
+ potentialAction: opts.searchUrlTemplate ? {
3182
+ "@type": "SearchAction",
3183
+ target: {
3184
+ "@type": "EntryPoint",
3185
+ urlTemplate: opts.searchUrlTemplate
3186
+ },
3187
+ "query-input": "required name=search_term_string"
3188
+ } : undefined
3189
+ };
3190
+ }
3130
3191
  }
3131
3192
 
3132
3193
  // src/matrix-engine.ts
@@ -3635,6 +3696,260 @@ class PseoMatrixEngine {
3635
3696
  return allPages;
3636
3697
  }
3637
3698
  }
3699
+ // src/brand-icons.ts
3700
+ var BRAND_ICONS = {
3701
+ facebook: {
3702
+ name: "Facebook",
3703
+ slug: "facebook",
3704
+ category: "social",
3705
+ viewBox: "0 0 24 24",
3706
+ svgPath: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z",
3707
+ brandColor: "#1877F2"
3708
+ },
3709
+ instagram: {
3710
+ name: "Instagram",
3711
+ slug: "instagram",
3712
+ category: "social",
3713
+ viewBox: "0 0 24 24",
3714
+ svgPath: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z",
3715
+ brandColor: "#E4405F"
3716
+ },
3717
+ linkedin: {
3718
+ name: "LinkedIn",
3719
+ slug: "linkedin",
3720
+ category: "social",
3721
+ viewBox: "0 0 24 24",
3722
+ svgPath: "M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z",
3723
+ brandColor: "#0A66C2"
3724
+ },
3725
+ twitter: {
3726
+ name: "X (Twitter)",
3727
+ slug: "twitter",
3728
+ category: "social",
3729
+ viewBox: "0 0 24 24",
3730
+ svgPath: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z",
3731
+ brandColor: "#000000"
3732
+ },
3733
+ youtube: {
3734
+ name: "YouTube",
3735
+ slug: "youtube",
3736
+ category: "social",
3737
+ viewBox: "0 0 24 24",
3738
+ svgPath: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z",
3739
+ brandColor: "#FF0000"
3740
+ },
3741
+ tiktok: {
3742
+ name: "TikTok",
3743
+ slug: "tiktok",
3744
+ category: "social",
3745
+ viewBox: "0 0 24 24",
3746
+ svgPath: "M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.24 1.07-.14 1.61.24 1.64 1.82 2.89 3.5 2.76 1.25-.04 2.4-1.02 2.68-2.22.12-.55.13-1.12.13-1.68V.02z",
3747
+ brandColor: "#000000"
3748
+ },
3749
+ shopify: {
3750
+ name: "Shopify",
3751
+ slug: "shopify",
3752
+ category: "ecommerce",
3753
+ viewBox: "0 0 24 24",
3754
+ svgPath: "M18.8 6.5l-1.3-.4c-.1-.3-.4-1.1-.7-1.5-.7-.9-1.7-1.4-2.8-1.4-.1 0-.2 0-.3.1l-.8-2.5c-.1-.4-.6-.6-.9-.4l-6.5 2.1c-.2.1-.3.2-.3.4l-.8 2.5-3.3 1c-.7.2-.9.9-.5 1.5l5.5 14.7c.2.4.6.7 1.1.7h11.1c.5 0 .9-.3 1.1-.7l3.6-14.8c.2-.7-.3-1.3-.9-1.2zm-5.7-1.9c.7 0 1.3.4 1.8 1.1.3.4.5 1 .6 1.3l-3.9 1.2 1.5-3.6zm-3.3 1.1l3.5-1.1-1.4 3.4-3.4-1.1 1.3-1.2z",
3755
+ brandColor: "#96BF48"
3756
+ },
3757
+ slack: {
3758
+ name: "Slack",
3759
+ slug: "slack",
3760
+ category: "tech",
3761
+ viewBox: "0 0 24 24",
3762
+ svgPath: "M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z",
3763
+ brandColor: "#4A154B"
3764
+ },
3765
+ whatsapp: {
3766
+ name: "WhatsApp",
3767
+ slug: "whatsapp",
3768
+ category: "social",
3769
+ viewBox: "0 0 24 24",
3770
+ svgPath: "M.057 24l1.687-6.163c-1.041-1.804-1.588-3.849-1.587-5.946.003-6.556 5.338-11.891 11.893-11.891 3.181.001 6.167 1.24 8.413 3.488 2.245 2.248 3.481 5.236 3.48 8.414-.003 6.557-5.338 11.892-11.893 11.892-1.99-.001-3.951-.5-5.688-1.448l-6.305 1.654zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884-.001 2.225.651 3.891 1.746 5.634l-.999 3.648 3.742-.981z",
3771
+ brandColor: "#25D366"
3772
+ },
3773
+ hubspot: {
3774
+ name: "HubSpot",
3775
+ slug: "hubspot",
3776
+ category: "crm",
3777
+ viewBox: "0 0 24 24",
3778
+ svgPath: "M17.48 7.37V4.92c.73-.37 1.23-1.12 1.23-2 0-1.24-1-2.24-2.24-2.24s-2.24 1-2.24 2.24c0 .88.5 1.63 1.23 2v2.45c-1.39.38-2.48 1.48-2.86 2.87H9.28c-.37-.5-1-.83-1.68-.83-.07 0-.15 0-.22.02V7.15c.61-.35 1.02-.99 1.02-1.74 0-1.1-.9-2-2-2s-2 .9-2 2c0 .75.41 1.39 1.02 1.74v2.28c-.68.22-1.19.8-1.31 1.52H2.24c-.2-.58-.75-1-1.4-1C.38 10 0 10.38 0 10.84s.38.84.84.84c.65 0 1.2-.42 1.4-1h1.87c.12.72.63 1.3 1.31 1.52v5.26c-.61.35-1.02.99-1.02 1.74 0 1.1.9 2 2 2s2-.9 2-2c0-.75-.41-1.39-1.02-1.74v-5.26c.07.02.15.02.22.02.68 0 1.31-.33 1.68-.83h3.32c.38 1.39 1.47 2.49 2.86 2.87v2.45c-.73.37-1.23 1.12-1.23 2 0 1.24 1 2.24 2.24 2.24s2.24-1 2.24-2.24c0-.88-.5-1.63-1.23-2v-2.45c1.84-.5 3.23-2.16 3.23-4.14s-1.39-3.64-3.23-4.14zm-1.01 6.13c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z",
3779
+ brandColor: "#FF7A59"
3780
+ },
3781
+ github: {
3782
+ name: "GitHub",
3783
+ slug: "github",
3784
+ category: "tech",
3785
+ viewBox: "0 0 24 24",
3786
+ svgPath: "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z",
3787
+ brandColor: "#181717"
3788
+ },
3789
+ google: {
3790
+ name: "Google",
3791
+ slug: "google",
3792
+ category: "tech",
3793
+ viewBox: "0 0 24 24",
3794
+ svgPath: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09zM12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23zm-6.16-8.9c-.22-.66-.35-1.36-.35-2.1s.13-1.44.35-2.1V7.06H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.94l2.85-2.22.81-.62zM12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.06l3.66 2.84c.87-2.6 3.3-4.52 6.16-4.52z",
3795
+ brandColor: "#4285F4"
3796
+ }
3797
+ };
3798
+ function resolveBrandIcon(input) {
3799
+ if (!input || typeof input !== "string")
3800
+ return;
3801
+ const clean = input.toLowerCase().replace(/[^a-z0-9]/g, "");
3802
+ for (const [key, icon] of Object.entries(BRAND_ICONS)) {
3803
+ if (clean.includes(key) || clean.includes(icon.slug)) {
3804
+ return icon;
3805
+ }
3806
+ }
3807
+ return;
3808
+ }
3809
+ function renderBrandIconSvg(input, className = "w-5 h-5 inline-block") {
3810
+ const icon = resolveBrandIcon(input);
3811
+ if (!icon)
3812
+ return "";
3813
+ return `<svg class="${className}" viewBox="${icon.viewBox}" fill="currentColor" aria-hidden="true"><path d="${icon.svgPath}"/></svg>`;
3814
+ }
3815
+ // src/urlytics-engine.ts
3816
+ class UrlyticsEngine {
3817
+ static parseUrl(rawUrl) {
3818
+ if (!rawUrl || typeof rawUrl !== "string") {
3819
+ return {
3820
+ url: "",
3821
+ scheme: "",
3822
+ domain: "",
3823
+ path: "/",
3824
+ depth: 0,
3825
+ lastDir: "",
3826
+ queryParams: {},
3827
+ slugTokens: [],
3828
+ charCount: 0,
3829
+ hasTrailingSlash: false
3830
+ };
3831
+ }
3832
+ try {
3833
+ const parsed = new URL(rawUrl.startsWith("http") ? rawUrl : `https://${rawUrl}`);
3834
+ const pathClean = parsed.pathname.replace(/\/+$/, "");
3835
+ const segments = pathClean.split("/").filter(Boolean);
3836
+ const queryParams = {};
3837
+ parsed.searchParams.forEach((val, key) => {
3838
+ queryParams[key] = val;
3839
+ });
3840
+ const lastDir = segments.length > 0 ? segments[segments.length - 1] : "";
3841
+ const slugTokens = lastDir.split("-").filter(Boolean);
3842
+ return {
3843
+ url: rawUrl,
3844
+ scheme: parsed.protocol.replace(":", ""),
3845
+ domain: parsed.hostname,
3846
+ path: parsed.pathname,
3847
+ depth: segments.length,
3848
+ dir1: segments[0],
3849
+ dir2: segments[1],
3850
+ dir3: segments[2],
3851
+ lastDir,
3852
+ queryParams,
3853
+ hashFragment: parsed.hash ? parsed.hash.replace("#", "") : undefined,
3854
+ slugTokens,
3855
+ charCount: rawUrl.length,
3856
+ hasTrailingSlash: parsed.pathname.length > 1 && parsed.pathname.endsWith("/")
3857
+ };
3858
+ } catch {
3859
+ return {
3860
+ url: rawUrl,
3861
+ scheme: "unknown",
3862
+ domain: "",
3863
+ path: rawUrl,
3864
+ depth: 0,
3865
+ lastDir: rawUrl,
3866
+ queryParams: {},
3867
+ slugTokens: [rawUrl],
3868
+ charCount: rawUrl.length,
3869
+ hasTrailingSlash: false
3870
+ };
3871
+ }
3872
+ }
3873
+ static analyzeUrls(urls) {
3874
+ return urls.map((u) => this.parseUrl(u));
3875
+ }
3876
+ }
3877
+ // src/keyword-permutator.ts
3878
+ class KeywordPermutatorEngine {
3879
+ static generateKeywordMatrix(options) {
3880
+ const { products, words = [], locations = [], maxCombinations = 5000 } = options;
3881
+ const results = [];
3882
+ const intentKeywords = {
3883
+ transactional: ["buy", "pricing", "cost", "hire", "quote", "tarif", "prix", "devis", "acheter"],
3884
+ commercial: ["best", "top", "review", "vs", "comparison", "alternative", "comparatif", "meilleur"],
3885
+ informational: ["how to", "what is", "guide", "tutorial", "definition", "comment", "quest ce que"],
3886
+ navigational: ["login", "app", "portal", "website", "connexion"]
3887
+ };
3888
+ const detectIntent = (text) => {
3889
+ const lower = text.toLowerCase();
3890
+ for (const [intent, triggers] of Object.entries(intentKeywords)) {
3891
+ if (triggers.some((t) => lower.includes(t))) {
3892
+ return intent;
3893
+ }
3894
+ }
3895
+ return "commercial";
3896
+ };
3897
+ for (const prod of products) {
3898
+ results.push({
3899
+ keyword: prod,
3900
+ exactMatch: `[${prod}]`,
3901
+ phraseMatch: `"${prod}"`,
3902
+ intent: detectIntent(prod),
3903
+ product: prod
3904
+ });
3905
+ for (const word of words) {
3906
+ const kw1 = `${word} ${prod}`;
3907
+ const kw2 = `${prod} ${word}`;
3908
+ results.push({
3909
+ keyword: kw1,
3910
+ exactMatch: `[${kw1}]`,
3911
+ phraseMatch: `"${kw1}"`,
3912
+ intent: detectIntent(word),
3913
+ product: prod,
3914
+ modifier: word
3915
+ });
3916
+ results.push({
3917
+ keyword: kw2,
3918
+ exactMatch: `[${kw2}]`,
3919
+ phraseMatch: `"${kw2}"`,
3920
+ intent: detectIntent(word),
3921
+ product: prod,
3922
+ modifier: word
3923
+ });
3924
+ for (const loc of locations) {
3925
+ const kwLoc1 = `${word} ${prod} ${loc}`;
3926
+ const kwLoc2 = `${prod} ${loc} ${word}`;
3927
+ results.push({
3928
+ keyword: kwLoc1,
3929
+ exactMatch: `[${kwLoc1}]`,
3930
+ phraseMatch: `"${kwLoc1}"`,
3931
+ intent: detectIntent(word),
3932
+ product: prod,
3933
+ modifier: word,
3934
+ location: loc
3935
+ });
3936
+ results.push({
3937
+ keyword: kwLoc2,
3938
+ exactMatch: `[${kwLoc2}]`,
3939
+ phraseMatch: `"${kwLoc2}"`,
3940
+ intent: detectIntent(word),
3941
+ product: prod,
3942
+ modifier: word,
3943
+ location: loc
3944
+ });
3945
+ if (results.length >= maxCombinations)
3946
+ return results;
3947
+ }
3948
+ }
3949
+ }
3950
+ return results;
3951
+ }
3952
+ }
3638
3953
  // src/llm-prompt.ts
3639
3954
  var PSEO_AGENT_SYSTEM_PROMPT = `
3640
3955
  You are the Programmatic SEO Implementation Specialist powered by @lynxflow/seo-engine.
@@ -3729,10 +4044,12 @@ export const PSEO_DATASET = {
3729
4044
  };
3730
4045
  \`\`\`
3731
4046
 
3732
- #### File 2: Universal Dynamic Catch-All Route (\`app/[...slug]/page.tsx\`)
4047
+ #### File 2: Ultra-Modern Dynamic Catch-All Route (\`app/[...slug]/page.tsx\`)
3733
4048
  \`\`\`tsx
3734
4049
  import { notFound } from "next/navigation";
4050
+ import Link from "next/link";
3735
4051
  import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
4052
+ import { renderBrandIconSvg } from "@lynxflow/seo-engine";
3736
4053
 
3737
4054
  export async function generateMetadata({ params }: { params: { slug: string[] } }) {
3738
4055
  const path = "/" + params.slug.join("/");
@@ -3750,12 +4067,75 @@ export default async function ProgrammaticPage({ params }: { params: { slug: str
3750
4067
  const page = pages.find((p) => p.urlPath === path);
3751
4068
  if (!page) notFound();
3752
4069
 
4070
+ // Automatic Brand Icon Detection
4071
+ const brandSvg = renderBrandIconSvg(page.integration?.name || page.competitor?.name || page.service?.name || "");
4072
+
3753
4073
  return (
3754
- <article className="max-w-4xl mx-auto py-12 px-6">
4074
+ <article className="min-h-screen bg-background text-foreground transition-colors duration-200">
4075
+ {/* 1. Official Google Schema.org JSON-LD */}
3755
4076
  <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(page.schemaGraph) }} />
3756
- <h1 className="text-4xl font-extrabold">{page.h1}</h1>
3757
- <p className="mt-4 text-xl text-gray-600">{page.description}</p>
3758
- {page.disclaimerText && <aside className="mt-8 p-4 bg-gray-50 border rounded text-xs text-gray-500">{page.disclaimerText}</aside>}
4077
+
4078
+ <main className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16 space-y-12">
4079
+ {/* 2. Hero Section with Glassmorphism Badge */}
4080
+ <header className="space-y-6 text-center md:text-left">
4081
+ <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full text-xs font-semibold bg-primary/10 text-primary border border-primary/20 backdrop-blur-md">
4082
+ {brandSvg && <span dangerouslySetInnerHTML={{ __html: brandSvg }} className="w-4 h-4 flex items-center" />}
4083
+ <span>{page.matrixFamily.toUpperCase()}</span>
4084
+ </div>
4085
+
4086
+ <h1 className="text-4xl sm:text-5xl lg:text-6xl font-black tracking-tight leading-tight">
4087
+ {page.h1}
4088
+ </h1>
4089
+ <p className="text-lg sm:text-xl text-muted-foreground max-w-3xl leading-relaxed">
4090
+ {page.description}
4091
+ </p>
4092
+ </header>
4093
+
4094
+ {/* 3. AEO / GEO Direct-Answer Callout Box (Optimized for ChatGPT & Perplexity Citations) */}
4095
+ <section className="p-6 md:p-8 rounded-2xl bg-card border border-border shadow-sm space-y-3" data-geo-extract="true">
4096
+ <div className="flex items-center gap-2 text-primary font-bold text-sm">
4097
+ <span>⚡</span>
4098
+ <span>Direct Summary & Key Takeaways</span>
4099
+ </div>
4100
+ <p className="text-base text-card-foreground leading-relaxed">
4101
+ {page.description}
4102
+ </p>
4103
+ </section>
4104
+
4105
+ {/* 4. Interactive Value & Feature Grid */}
4106
+ <section className="grid grid-cols-1 md:grid-cols-3 gap-6">
4107
+ {(page.service?.keyFeatures || ["Real-time Sync", "Bank-grade Security", "Zero Lock-in"]).map((feat, idx) => (
4108
+ <div key={idx} className="p-6 rounded-xl bg-card/60 border border-border/80 hover:border-primary/50 transition duration-200 space-y-2">
4109
+ <div className="w-8 h-8 rounded-lg bg-primary/10 text-primary flex items-center justify-center font-bold text-sm">
4110
+ 0{idx + 1}
4111
+ </div>
4112
+ <h3 className="font-bold text-lg">{feat}</h3>
4113
+ <p className="text-sm text-muted-foreground">Automated workflows engineered for high-performance scale.</p>
4114
+ </div>
4115
+ ))}
4116
+ </section>
4117
+
4118
+ {/* 5. Geodesic Mesh Linking Footer (Prevents Orphan Pages & Spreads PageRank) */}
4119
+ {page.neighboringLinks && page.neighboringLinks.length > 0 && (
4120
+ <nav className="pt-8 border-t border-border space-y-4">
4121
+ <h3 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">Nearby & Related Hubs</h3>
4122
+ <div className="flex flex-wrap gap-2">
4123
+ {page.neighboringLinks.map((link, idx) => (
4124
+ <Link key={idx} href={link.url} className="px-3 py-1.5 rounded-lg text-xs font-medium bg-secondary text-secondary-foreground hover:bg-primary hover:text-primary-foreground transition duration-150">
4125
+ {link.name}
4126
+ </Link>
4127
+ ))}
4128
+ </div>
4129
+ </nav>
4130
+ )}
4131
+
4132
+ {/* 6. SeedRank Legal Compliance Notice */}
4133
+ {page.disclaimerText && (
4134
+ <aside className="p-4 rounded-lg bg-muted/40 border border-border text-xs text-muted-foreground leading-relaxed">
4135
+ {page.disclaimerText}
4136
+ </aside>
4137
+ )}
4138
+ </main>
3759
4139
  </article>
3760
4140
  );
3761
4141
  }