@lynxflow/seo-engine 1.8.29 → 2.0.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.
Files changed (96) hide show
  1. package/README.md +47 -93
  2. package/dist/ai-copilot-client.d.ts +2 -0
  3. package/dist/built-in-locations.d.ts +18 -0
  4. package/dist/content-ai-arsenal.d.ts +28 -0
  5. package/dist/existing-media-harvester.d.ts +33 -0
  6. package/dist/extended-schemas.d.ts +84 -0
  7. package/dist/features-knowledge-harvester.d.ts +56 -0
  8. package/dist/geo-citation-scorer.d.ts +34 -0
  9. package/dist/i18n-detector.d.ts +1 -1
  10. package/dist/index.d.ts +32 -7
  11. package/dist/index.js +538 -82
  12. package/dist/index.mjs +2028 -163
  13. package/dist/internal-pagerank-graph.d.ts +59 -0
  14. package/dist/knowledge-bank-builder.d.ts +91 -0
  15. package/dist/marketing-skills-engine.d.ts +74 -0
  16. package/dist/matrix-engine.d.ts +26 -0
  17. package/dist/power-words-psychology.d.ts +27 -15
  18. package/dist/public-manifest-engine.d.ts +58 -0
  19. package/dist/rag-knowledge-engine.d.ts +50 -0
  20. package/dist/rate-limited-translator.d.ts +19 -0
  21. package/dist/token-quota-manager.d.ts +4 -0
  22. package/package.json +11 -3
  23. package/TUTORIEL_INTEGRATION_SITE.md +0 -283
  24. package/connectors/cloudflare-worker/worker.js +0 -106
  25. package/connectors/laravel/LynxSeoController.php +0 -37
  26. package/connectors/wordpress/lynxseo-admin-app.js +0 -2618
  27. package/connectors/wordpress/lynxseo-connector.php +0 -1712
  28. package/connectors/wordpress/lynxseo-connector.zip +0 -0
  29. package/lynxflow-seo-engine-1.2.0.tgz +0 -0
  30. package/src/ad-intelligence-cro.ts +0 -140
  31. package/src/ai-bots-log-analyzer.ts +0 -127
  32. package/src/ai-copilot-client.ts +0 -99
  33. package/src/analytics-client.ts +0 -315
  34. package/src/auth-key.ts +0 -262
  35. package/src/backlinks-client.ts +0 -85
  36. package/src/brand-dna-calendar.ts +0 -120
  37. package/src/brand-icons.ts +0 -138
  38. package/src/built-in-locations.ts +0 -170
  39. package/src/content-ai-arsenal.ts +0 -268
  40. package/src/copy-frameworks-master.ts +0 -89
  41. package/src/cro-copywriting-engine.ts +0 -105
  42. package/src/crosslink-scorer.ts +0 -101
  43. package/src/embeddable-seo-widget.ts +0 -57
  44. package/src/engine.test.ts +0 -386
  45. package/src/engine.ts +0 -813
  46. package/src/existing-media-harvester.ts +0 -98
  47. package/src/extended-schemas.ts +0 -589
  48. package/src/features-knowledge-harvester.ts +0 -190
  49. package/src/free-public-tools.ts +0 -224
  50. package/src/geo-mesh-linking.ts +0 -93
  51. package/src/google-business-profile.ts +0 -280
  52. package/src/i18n-detector.ts +0 -98
  53. package/src/i18n-dictionary.ts +0 -422
  54. package/src/index.ts +0 -164
  55. package/src/indexnow-client.ts +0 -94
  56. package/src/instant-matrix-search.ts +0 -48
  57. package/src/isr-cache-manager.ts +0 -78
  58. package/src/keyword-permutator.ts +0 -118
  59. package/src/knowledge-bank-builder.ts +0 -299
  60. package/src/knowledge-graph-linker.ts +0 -81
  61. package/src/lago-token-meter.ts +0 -120
  62. package/src/legal-disclaimers.ts +0 -407
  63. package/src/llm-content-cleaner.ts +0 -64
  64. package/src/llm-prompt.ts +0 -323
  65. package/src/master-marketing-engine.ts +0 -314
  66. package/src/matrix-engine.ts +0 -1204
  67. package/src/mcp-seo-server.ts +0 -108
  68. package/src/ngram-density-analyzer.ts +0 -108
  69. package/src/og-image-generator.ts +0 -109
  70. package/src/power-words-psychology.ts +0 -369
  71. package/src/public-manifest-engine.ts +0 -109
  72. package/src/rag-knowledge-engine.ts +0 -163
  73. package/src/rank-math-parity.ts +0 -235
  74. package/src/rate-limited-translator.ts +0 -110
  75. package/src/real-reviews-sync.ts +0 -207
  76. package/src/rss-syndication-feed.ts +0 -56
  77. package/src/schema-builder.ts +0 -134
  78. package/src/seo-opportunities-decay.ts +0 -154
  79. package/src/serp-client.ts +0 -89
  80. package/src/serp-history-alerts.ts +0 -75
  81. package/src/site-auditor.ts +0 -83
  82. package/src/site-crawler.ts +0 -406
  83. package/src/slug-engine.ts +0 -183
  84. package/src/social-ads-seo.ts +0 -211
  85. package/src/social-growth-suite.ts +0 -310
  86. package/src/social-trend-seo.ts +0 -103
  87. package/src/social-video-seo.ts +0 -100
  88. package/src/team-rbac.ts +0 -61
  89. package/src/technical-rules-auditor.ts +0 -171
  90. package/src/token-quota-manager.ts +0 -91
  91. package/src/types.ts +0 -143
  92. package/src/ui-icons.ts +0 -134
  93. package/src/urlytics-engine.ts +0 -97
  94. package/src/video-youtube-analyzer.ts +0 -81
  95. package/src/yoast-parity.ts +0 -161
  96. package/tsconfig.json +0 -15
@@ -1,100 +0,0 @@
1
- /**
2
- * 🎬 Video & Social SEO Analytics Engine (YouTube, TikTok, Instagram Reels)
3
- *
4
- * Tracks video rankings in Google Video Carousels and YouTube/TikTok Search,
5
- * measures search attribution, and generates Google-compliant Schema.org `VideoObject` graphs.
6
- */
7
-
8
- export interface TrackedVideoRecord {
9
- id: string;
10
- platform: "youtube" | "tiktok" | "instagram-reels";
11
- title: string;
12
- videoUrl: string;
13
- thumbnailUrl: string;
14
- views: number;
15
- likes: number;
16
- shares: number;
17
- commentsCount: number;
18
- durationSec: number;
19
- publishedAt: string;
20
- targetKeywords: string[];
21
- googleVideoCarouselRank?: number; // e.g. #1 in Google Video Carousel
22
- youtubeSearchRank?: number;
23
- tiktokSearchRank?: number;
24
- associatedLandingPageUrl?: string;
25
- estimatedSearchVisitsGenerated: number;
26
- }
27
-
28
- export interface VideoSchemaOpts {
29
- name: string;
30
- description: string;
31
- thumbnailUrl: string;
32
- uploadDate: string;
33
- contentUrl: string;
34
- embedUrl: string;
35
- durationIso: string; // e.g. "PT1M45S"
36
- transcript?: string;
37
- chapters?: { name: string; startOffsetSeconds: number }[];
38
- }
39
-
40
- export class SocialVideoSeoAnalyticsEngine {
41
- /**
42
- * Generates a Google-verified Schema.org `VideoObject` with chapters (Clip / SeekToAction).
43
- */
44
- static buildVideoObjectSchema(opts: VideoSchemaOpts): Record<string, unknown> {
45
- const schema: Record<string, unknown> = {
46
- "@context": "https://schema.org",
47
- "@type": "VideoObject",
48
- name: opts.name,
49
- description: opts.description,
50
- thumbnailUrl: [opts.thumbnailUrl],
51
- uploadDate: opts.uploadDate,
52
- contentUrl: opts.contentUrl,
53
- embedUrl: opts.embedUrl,
54
- duration: opts.durationIso,
55
- transcript: opts.transcript,
56
- };
57
-
58
- if (opts.chapters && opts.chapters.length > 0) {
59
- schema.hasPart = opts.chapters.map((ch, idx) => ({
60
- "@type": "Clip",
61
- name: ch.name,
62
- startOffset: ch.startOffsetSeconds,
63
- endOffset:
64
- idx < opts.chapters!.length - 1
65
- ? opts.chapters![idx + 1].startOffsetSeconds
66
- : ch.startOffsetSeconds + 30,
67
- url: `${opts.contentUrl}?t=${ch.startOffsetSeconds}`,
68
- }));
69
- }
70
-
71
- return schema;
72
- }
73
-
74
- /**
75
- * Analyzes an array of videos to calculate total social reach and search traffic attribution.
76
- */
77
- static calculateVideoPortfolioStats(videos: TrackedVideoRecord[]) {
78
- const totalViews = videos.reduce((acc, v) => acc + v.views, 0);
79
- const totalEngagement = videos.reduce((acc, v) => acc + (v.likes + v.shares + v.commentsCount), 0);
80
- const inGoogleCarouselCount = videos.filter((v) => Boolean(v.googleVideoCarouselRank)).length;
81
- const totalSearchVisits = videos.reduce((acc, v) => acc + v.estimatedSearchVisitsGenerated, 0);
82
-
83
- const platformBreakdown = {
84
- youtube: videos.filter((v) => v.platform === "youtube").length,
85
- tiktok: videos.filter((v) => v.platform === "tiktok").length,
86
- instagram: videos.filter((v) => v.platform === "instagram-reels").length,
87
- };
88
-
89
- return {
90
- totalVideosTracked: videos.length,
91
- totalViews,
92
- totalEngagement,
93
- avgEngagementRate: totalViews > 0 ? Math.round((totalEngagement / totalViews) * 1000) / 10 : 0,
94
- inGoogleCarouselCount,
95
- totalSearchVisits,
96
- platformBreakdown,
97
- topPerformingVideos: [...videos].sort((a, b) => b.views - a.views).slice(0, 5),
98
- };
99
- }
100
- }
package/src/team-rbac.ts DELETED
@@ -1,61 +0,0 @@
1
- /**
2
- * 👥 Team IAM & Multi-User RBAC Engine (Issue #87)
3
- *
4
- * Provides granular permissions per team member across SEO projects:
5
- * - `owner`: Full project control, billing, domain deletion.
6
- * - `admin`: Add/remove tracked keywords, run crawls, edit AI prompts.
7
- * - `editor`: View rankings, generate pSEO pages, run audits.
8
- * - `viewer`: Read-only access to dashboards and CSV exports.
9
- */
10
-
11
- export type TeamRole = "owner" | "admin" | "editor" | "viewer";
12
-
13
- export type PermissionAction =
14
- | "project:delete"
15
- | "project:update"
16
- | "keywords:add"
17
- | "keywords:delete"
18
- | "keywords:export"
19
- | "audit:run"
20
- | "pseo:generate"
21
- | "ai_copilot:execute";
22
-
23
- const ROLE_PERMISSIONS: Record<TeamRole, PermissionAction[]> = {
24
- owner: [
25
- "project:delete",
26
- "project:update",
27
- "keywords:add",
28
- "keywords:delete",
29
- "keywords:export",
30
- "audit:run",
31
- "pseo:generate",
32
- "ai_copilot:execute",
33
- ],
34
- admin: [
35
- "project:update",
36
- "keywords:add",
37
- "keywords:delete",
38
- "keywords:export",
39
- "audit:run",
40
- "pseo:generate",
41
- "ai_copilot:execute",
42
- ],
43
- editor: [
44
- "keywords:add",
45
- "keywords:export",
46
- "audit:run",
47
- "pseo:generate",
48
- "ai_copilot:execute",
49
- ],
50
- viewer: ["keywords:export"],
51
- };
52
-
53
- export class TeamRbacEngine {
54
- /**
55
- * Checks if a user role has permission to perform an action.
56
- */
57
- static can(role: TeamRole, action: PermissionAction): boolean {
58
- const permissions = ROLE_PERMISSIONS[role] || [];
59
- return permissions.includes(action);
60
- }
61
- }
@@ -1,171 +0,0 @@
1
- /**
2
- * 🔬 Technical SEO Rules Auditor (Inspiration: seonaut/internal/issues/)
3
- *
4
- * Implements strict, production-grade automated checks:
5
- * 1. Heading Hierarchy Integrity (Missing H1, Multiple H1s, Hierarchy Gaps like H1->H3)
6
- * 2. Redirect Chain & Loop Detection (301/302 > 1 hop)
7
- * 3. Thin Content Detection (< 300 words)
8
- * 4. Canonical URL Auditing (Missing, relative, mismatched)
9
- * 5. Hreflang Symmetrical Validation (Missing return tags)
10
- * 6. Image Optimization (Missing Alt text, heavy assets > 100KB)
11
- */
12
-
13
- export interface PageAuditInput {
14
- url: string;
15
- statusCode: number;
16
- headings: { tag: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; text: string }[];
17
- wordCount: number;
18
- canonicalUrl?: string;
19
- hreflangs?: { lang: string; url: string }[];
20
- images?: { src: string; alt?: string; sizeBytes?: number }[];
21
- redirectChain?: { url: string; statusCode: number }[];
22
- timeToFirstByteMs?: number;
23
- }
24
-
25
- export type IssueSeverity = "critical" | "warning" | "info";
26
-
27
- export interface TechnicalIssue {
28
- code: string;
29
- category: "headings" | "redirects" | "content" | "canonical" | "hreflang" | "images" | "performance";
30
- severity: IssueSeverity;
31
- title: string;
32
- description: string;
33
- recommendation: string;
34
- }
35
-
36
- export class TechnicalRulesAuditor {
37
- /**
38
- * Audits a single page payload across all technical rules.
39
- */
40
- static auditPage(page: PageAuditInput): TechnicalIssue[] {
41
- const issues: TechnicalIssue[] = [];
42
-
43
- // 1. Heading Hierarchy Audit
44
- const h1s = page.headings.filter((h) => h.tag === "h1");
45
- if (h1s.length === 0) {
46
- issues.push({
47
- code: "HEADING_H1_MISSING",
48
- category: "headings",
49
- severity: "critical",
50
- title: "Balise <h1> manquante",
51
- description: `Aucune balise <h1> trouvée sur ${page.url}.`,
52
- recommendation: "Ajoutez exactement une balise <h1> contenant votre mot-clé principal.",
53
- });
54
- } else if (h1s.length > 1) {
55
- issues.push({
56
- code: "HEADING_H1_MULTIPLE",
57
- category: "headings",
58
- severity: "warning",
59
- title: "Multiples balises <h1> détectées",
60
- description: `La page contient ${h1s.length} balises <h1>.`,
61
- recommendation: "Conservez une seule balise <h1> principale et convertissez les autres en <h2>.",
62
- });
63
- }
64
-
65
- // Check heading hierarchy gaps (e.g. H1 followed immediately by H3 without H2)
66
- for (let i = 0; i < page.headings.length - 1; i++) {
67
- const currentLevel = parseInt(page.headings[i].tag.replace("h", ""), 10);
68
- const nextLevel = parseInt(page.headings[i + 1].tag.replace("h", ""), 10);
69
- if (nextLevel - currentLevel > 1) {
70
- issues.push({
71
- code: "HEADING_HIERARCHY_GAP",
72
- category: "headings",
73
- severity: "warning",
74
- title: "Saut dans la hiérarchie des titres",
75
- description: `Passage direct de <${page.headings[i].tag}> à <${page.headings[i + 1].tag}> sans niveau intermédiaire.`,
76
- recommendation: "Respectez l'arborescence logique des titres (H1 ➔ H2 ➔ H3).",
77
- });
78
- break;
79
- }
80
- }
81
-
82
- // 2. Redirect Chain & Loop Audit
83
- if (page.redirectChain && page.redirectChain.length > 1) {
84
- const isLoop = new Set(page.redirectChain.map((r) => r.url)).size < page.redirectChain.length;
85
- if (isLoop) {
86
- issues.push({
87
- code: "REDIRECT_LOOP",
88
- category: "redirects",
89
- severity: "critical",
90
- title: "Boucle de redirection infinie",
91
- description: `Boucle de redirection détectée sur ${page.url}.`,
92
- recommendation: "Corrigez la configuration de redirection pour pointer directement vers l'URL finale.",
93
- });
94
- } else {
95
- issues.push({
96
- code: "REDIRECT_CHAIN",
97
- category: "redirects",
98
- severity: "warning",
99
- title: "Chaîne de redirection (> 1 saut)",
100
- description: `La redirection traverse ${page.redirectChain.length} étapes successives.`,
101
- recommendation: "Redirigez directement de l'URL initiale vers la destination finale en 1 seul saut 301.",
102
- });
103
- }
104
- }
105
-
106
- // 3. Thin Content Detection (< 300 words)
107
- if (page.wordCount < 300 && page.statusCode === 200) {
108
- issues.push({
109
- code: "CONTENT_THIN",
110
- category: "content",
111
- severity: "critical",
112
- title: "Contenu trop faible (Thin Content)",
113
- description: `La page ne contient que ${page.wordCount} mots (seuil minimum recommandé : 300 mots).`,
114
- recommendation: "Enrichissez la page avec du contenu textuel informatif, FAQs et preuves sociales.",
115
- });
116
- }
117
-
118
- // 4. Canonical Auditing
119
- if (!page.canonicalUrl && page.statusCode === 200) {
120
- issues.push({
121
- code: "CANONICAL_MISSING",
122
- category: "canonical",
123
- severity: "warning",
124
- title: "Balise canonique manquante",
125
- description: `Aucune balise <link rel="canonical"> n'est déclarée.`,
126
- recommendation: "Ajoutez une URL canonique absolue pointant vers la version officielle de la page.",
127
- });
128
- }
129
-
130
- // 5. Image Optimization & Alt Attributes
131
- if (page.images) {
132
- const missingAlts = page.images.filter((img) => !img.alt || img.alt.trim() === "");
133
- if (missingAlts.length > 0) {
134
- issues.push({
135
- code: "IMAGES_ALT_MISSING",
136
- category: "images",
137
- severity: "warning",
138
- title: "Images sans texte alternatif (alt)",
139
- description: `${missingAlts.length} image(s) n'ont pas d'attribut alt renseigné.`,
140
- recommendation: "Renseignez des descriptions textuelles précises pour l'accessibilité et Google Images.",
141
- });
142
- }
143
-
144
- const heavyImages = page.images.filter((img) => (img.sizeBytes || 0) > 100_000);
145
- if (heavyImages.length > 0) {
146
- issues.push({
147
- code: "IMAGES_HEAVY",
148
- category: "images",
149
- severity: "info",
150
- title: "Images trop lourdes (> 100 KB)",
151
- description: `${heavyImages.length} image(s) dépassent 100 KB.`,
152
- recommendation: "Convertissez vos images au format moderne WebP / AVIF et compressez-les.",
153
- });
154
- }
155
- }
156
-
157
- // 6. Time To First Byte (TTFB)
158
- if (page.timeToFirstByteMs && page.timeToFirstByteMs > 500) {
159
- issues.push({
160
- code: "PERF_HIGH_TTFB",
161
- category: "performance",
162
- severity: "warning",
163
- title: "Temps de réponse serveur élevé (TTFB > 500ms)",
164
- description: `Le TTFB mesuré est de ${page.timeToFirstByteMs}ms.`,
165
- recommendation: "Activez la mise en cache Edge CDN (Cloudflare) ou l'ISR Next.js pour passer sous 50ms.",
166
- });
167
- }
168
-
169
- return issues;
170
- }
171
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * 🪙 Token Quota & Credit Billing Bridge
3
- *
4
- * Synchronizes with LynxFlow's official TokenBillingService & CreditService (1$ = 100 credits).
5
- * Manages tenant monthly quotas, OpenRouter raw provider costs, and credit balances.
6
- */
7
-
8
- export interface TokenUsageRecord {
9
- promptTokens: number;
10
- completionTokens: number;
11
- totalTokens: number;
12
- creditsCharged: number;
13
- model: string;
14
- timestamp: string;
15
- }
16
-
17
- export interface CreditQuotaStatus {
18
- tier: "starter" | "growth" | "enterprise";
19
- monthlyCreditBudget: number; // e.g. 5,000 credits ($50) for Growth, 50,000 credits ($500) for Enterprise
20
- usedCredits: number;
21
- remainingCredits: number;
22
- isQuotaExceeded: boolean;
23
- }
24
-
25
- export class TokenQuotaManager {
26
- private tier: "starter" | "growth" | "enterprise";
27
- private monthlyCreditBudget: number;
28
- private usedCredits: number = 0;
29
-
30
- constructor(tier: "starter" | "growth" | "enterprise" = "enterprise") {
31
- this.tier = tier;
32
- this.monthlyCreditBudget = this.resolveBudget(tier);
33
- }
34
-
35
- private resolveBudget(tier: "starter" | "growth" | "enterprise"): number {
36
- switch (tier) {
37
- case "enterprise":
38
- return 50_000; // 50,000 credits ($500/mo)
39
- case "growth":
40
- return 5_000; // 5,000 credits ($50/mo)
41
- case "starter":
42
- default:
43
- return 500; // 500 credits ($5/mo)
44
- }
45
- }
46
-
47
- /**
48
- * Records token usage and calculates LynxFlow Credit cost (1$ = 100 credits).
49
- * Only charges credits when AI call succeeds (Issue #222 fix).
50
- */
51
- consumeTokens(
52
- promptTokens: number,
53
- completionTokens: number,
54
- model: string,
55
- rawProviderCostUsd = 0.002, // Default ~$0.002 per 1k tokens
56
- ): TokenUsageRecord {
57
- const totalTokens = promptTokens + completionTokens;
58
-
59
- // LynxFlow standard: Provider cost + 20% margin converted to credits (1$ = 100cr)
60
- const costWithMarginUsd = rawProviderCostUsd * (totalTokens / 1000) * 1.2;
61
- const creditsCharged = Math.max(1, Math.ceil(costWithMarginUsd * 100));
62
-
63
- this.usedCredits += creditsCharged;
64
-
65
- if (this.usedCredits > this.monthlyCreditBudget) {
66
- console.warn(`⚠️ [LynxFlow Credit Quota] Monthly credit budget exceeded (${this.usedCredits} / ${this.monthlyCreditBudget} cr). Switching to zero-cost algorithmic mode.`);
67
- }
68
-
69
- return {
70
- promptTokens,
71
- completionTokens,
72
- totalTokens,
73
- creditsCharged,
74
- model,
75
- timestamp: new Date().toISOString(),
76
- };
77
- }
78
-
79
- /**
80
- * Gets current credit quota status.
81
- */
82
- getStatus(): CreditQuotaStatus {
83
- return {
84
- tier: this.tier,
85
- monthlyCreditBudget: this.monthlyCreditBudget,
86
- usedCredits: this.usedCredits,
87
- remainingCredits: Math.max(0, this.monthlyCreditBudget - this.usedCredits),
88
- isQuotaExceeded: this.usedCredits >= this.monthlyCreditBudget,
89
- };
90
- }
91
- }
package/src/types.ts DELETED
@@ -1,143 +0,0 @@
1
- /**
2
- * 🌟 Types & Interfaces for @lynxflow/seo-engine Universal SDK
3
- *
4
- * Full Institutional pSEO Type System matching LynxFlow's 8 Programmatic Matrices:
5
- * 1. 📍 Local & GEO : [Pillar/Service] × [City/Country]
6
- * 2. 🥊 VS & Comparatifs : [Brand/Service] vs [Competitor]
7
- * 3. 🔄 Alternatives : [Competitor] ➔ [Brand/Service]
8
- * 4. 🏢 Secteurs & Métiers : [Service] × [Industry Vertical] (with localized ROI)
9
- * 5. 🔌 Intégrations : [Service] × [Third-party Software]
10
- * 6. 👤 Personas & Décideurs : [Service] × [Decision Maker Role]
11
- * 7. 🎯 Cas d'Usage : [Problem Statement] ➔ [AI Workflow Solution]
12
- * 8. 🧮 Simulateurs & Outils : Interactive ROI & Time-Savings Calculators
13
- */
14
-
15
- export interface LynxServiceDefinition {
16
- slug: string;
17
- name: string;
18
- description?: string;
19
- pricePerMonth: number;
20
- category?: string;
21
- features?: string[];
22
- faqs?: { question: string; answer: string }[];
23
- }
24
-
25
- import type {
26
- PseoIndustry,
27
- PseoCompetitor,
28
- PseoIntegration,
29
- PseoUseCase,
30
- PseoPersona,
31
- PseoService,
32
- PseoLocation,
33
- PseoCalculator,
34
- } from "./matrix-engine";
35
-
36
- export type {
37
- PseoIndustry,
38
- PseoCompetitor,
39
- PseoIntegration,
40
- PseoUseCase,
41
- PseoPersona,
42
- PseoService,
43
- PseoLocation,
44
- PseoCalculator,
45
- };
46
-
47
- export interface PseoCity {
48
- slug: string;
49
- name: string;
50
- region: string;
51
- country: string;
52
- department?: string;
53
- densityTier?: "major" | "secondary" | "regional";
54
- }
55
-
56
- export interface PseoCountry {
57
- code: string;
58
- name: string;
59
- currency: string;
60
- currencySymbol: string;
61
- locale: string;
62
- economicMultiplier: number;
63
- }
64
-
65
- export interface LynxSeoConfig {
66
- apiKey?: string;
67
- licenseKey?: string; // Deprecated: use apiKey
68
- domain: string;
69
- brandName: string;
70
- category?: string;
71
- defaultLocale?: string;
72
- supportedLocales?: string[];
73
- currency?: string;
74
- currencySymbol?: string;
75
- services: LynxServiceDefinition[];
76
- industries?: PseoIndustry[];
77
- competitors?: PseoCompetitor[];
78
- integrations?: PseoIntegration[];
79
- personas?: PseoPersona[];
80
- useCases?: PseoUseCase[];
81
- cities?: PseoCity[];
82
- locations?: PseoLocation[];
83
- phone?: string;
84
- }
85
-
86
- export interface LynxResolvedPage {
87
- url: string;
88
- title: string;
89
- description: string;
90
- h1: string;
91
- directAnswer: string;
92
- locale?: string;
93
- hreflangs?: { lang: string; url: string }[];
94
- faqs: { question: string; answer: string }[];
95
- jsonLd: Record<string, unknown>;
96
- htmlBody: string;
97
- markdownBody: string;
98
- executionTimeMs: number;
99
-
100
- // Localized ROI data (when applicable)
101
- localizedRoi?: {
102
- monthlySavingsFormatted: string;
103
- hoursSavedWeekly: number;
104
- annualSavingsFormatted: string;
105
- currencySymbol: string;
106
- };
107
-
108
- // Structured component data
109
- service?: LynxServiceDefinition;
110
- industry?: PseoIndustry;
111
- competitor?: PseoCompetitor;
112
- integration?: PseoIntegration;
113
-
114
- meta?: {
115
- title: string;
116
- description: string;
117
- h1: string;
118
- canonical: string;
119
- openGraphImageUrl?: string;
120
- };
121
-
122
- // Backward compatibility convenience fields
123
- fullUrl?: string;
124
- schemaJsonLd?: Record<string, unknown>;
125
- content?: {
126
- directAnswerGeoHtml?: string;
127
- heroHeadline?: string;
128
- heroSubheadline?: string;
129
- markdownBody?: string;
130
- faqList?: { question: string; answer: string }[];
131
- };
132
- pricing?: {
133
- priceNumber?: number;
134
- priceFormatted?: string;
135
- currency?: string;
136
- };
137
-
138
- debug?: {
139
- licenseStatus?: "active" | "trial" | "expired" | "offline_mode";
140
- generationMs?: number;
141
- matrixType?: string;
142
- };
143
- }