@lynxflow/seo-engine 1.4.0 β†’ 1.5.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 (86) hide show
  1. package/README.md +84 -339
  2. package/TUTORIEL_INTEGRATION_SITE.md +283 -0
  3. package/connectors/wordpress/lynxseo-connector.php +5 -5
  4. package/connectors/wordpress/lynxseo-connector.zip +0 -0
  5. package/dist/ad-intelligence-cro.d.ts +58 -0
  6. package/dist/ai-bots-log-analyzer.d.ts +36 -0
  7. package/dist/analytics-client.d.ts +48 -11
  8. package/dist/auth-key.d.ts +9 -0
  9. package/dist/brand-dna-calendar.d.ts +35 -0
  10. package/dist/copy-frameworks-master.d.ts +56 -0
  11. package/dist/cro-copywriting-engine.d.ts +46 -0
  12. package/dist/crosslink-scorer.d.ts +33 -0
  13. package/dist/embeddable-seo-widget.d.ts +12 -0
  14. package/dist/engine.d.ts +32 -1
  15. package/dist/engine.test.d.ts +1 -0
  16. package/dist/extended-schemas.d.ts +106 -0
  17. package/dist/geo-mesh-linking.d.ts +33 -0
  18. package/dist/index.d.ts +88 -0
  19. package/dist/index.js +4164 -130
  20. package/dist/index.mjs +4092 -100
  21. package/dist/instant-matrix-search.d.ts +19 -0
  22. package/dist/isr-cache-manager.d.ts +35 -0
  23. package/dist/knowledge-graph-linker.d.ts +29 -0
  24. package/dist/legal-disclaimers.d.ts +46 -0
  25. package/dist/llm-content-cleaner.d.ts +16 -0
  26. package/dist/llm-prompt.d.ts +13 -0
  27. package/dist/master-marketing-engine.d.ts +114 -0
  28. package/dist/matrix-engine.d.ts +201 -0
  29. package/dist/mcp-seo-server.d.ts +21 -0
  30. package/dist/ngram-density-analyzer.d.ts +35 -0
  31. package/dist/rank-math-parity.d.ts +58 -0
  32. package/dist/real-reviews-sync.d.ts +73 -0
  33. package/dist/rss-syndication-feed.d.ts +25 -0
  34. package/dist/schema-builder.d.ts +6 -0
  35. package/dist/seo-opportunities-decay.d.ts +54 -0
  36. package/dist/serp-history-alerts.d.ts +27 -0
  37. package/dist/slug-engine.d.ts +32 -0
  38. package/dist/social-ads-seo.d.ts +77 -0
  39. package/dist/social-growth-suite.d.ts +125 -0
  40. package/dist/social-trend-seo.d.ts +38 -0
  41. package/dist/social-video-seo.d.ts +62 -0
  42. package/dist/team-rbac.d.ts +17 -0
  43. package/dist/technical-rules-auditor.d.ts +50 -0
  44. package/dist/types.d.ts +4 -44
  45. package/dist/yoast-parity.d.ts +45 -0
  46. package/package.json +8 -5
  47. package/src/ad-intelligence-cro.ts +140 -0
  48. package/src/ai-bots-log-analyzer.ts +127 -0
  49. package/src/analytics-client.ts +222 -48
  50. package/src/auth-key.ts +60 -1
  51. package/src/brand-dna-calendar.ts +120 -0
  52. package/src/copy-frameworks-master.ts +89 -0
  53. package/src/cro-copywriting-engine.ts +105 -0
  54. package/src/crosslink-scorer.ts +101 -0
  55. package/src/embeddable-seo-widget.ts +57 -0
  56. package/src/engine.test.ts +136 -0
  57. package/src/engine.ts +229 -28
  58. package/src/extended-schemas.ts +279 -0
  59. package/src/geo-mesh-linking.ts +93 -0
  60. package/src/index.ts +89 -0
  61. package/src/instant-matrix-search.ts +48 -0
  62. package/src/isr-cache-manager.ts +78 -0
  63. package/src/knowledge-graph-linker.ts +81 -0
  64. package/src/legal-disclaimers.ts +407 -0
  65. package/src/llm-content-cleaner.ts +64 -0
  66. package/src/llm-prompt.ts +70 -0
  67. package/src/master-marketing-engine.ts +314 -0
  68. package/src/matrix-engine.ts +818 -0
  69. package/src/mcp-seo-server.ts +108 -0
  70. package/src/ngram-density-analyzer.ts +108 -0
  71. package/src/rank-math-parity.ts +235 -0
  72. package/src/real-reviews-sync.ts +207 -0
  73. package/src/rss-syndication-feed.ts +56 -0
  74. package/src/schema-builder.ts +71 -24
  75. package/src/seo-opportunities-decay.ts +154 -0
  76. package/src/serp-history-alerts.ts +75 -0
  77. package/src/slug-engine.ts +183 -0
  78. package/src/social-ads-seo.ts +211 -0
  79. package/src/social-growth-suite.ts +310 -0
  80. package/src/social-trend-seo.ts +103 -0
  81. package/src/social-video-seo.ts +100 -0
  82. package/src/team-rbac.ts +61 -0
  83. package/src/technical-rules-auditor.ts +171 -0
  84. package/src/types.ts +22 -47
  85. package/src/yoast-parity.ts +161 -0
  86. package/tsconfig.json +2 -1
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { cleanSeoSlug, validateSeoSlug, MULTILINGUAL_STOP_WORDS } from "./slug-engine";
3
+ import { LegalDisclaimerEngine, MULTILINGUAL_BANNED_DISPARAGING_WORDS } from "./legal-disclaimers";
4
+ import { ExtendedSchemaGraphBuilder } from "./extended-schemas";
5
+ import { PseoMatrixEngine } from "./matrix-engine";
6
+ import { getSeoAgentPrompt } from "./llm-prompt";
7
+
8
+ describe("Multilingual SEO Slug Engine (10+ Languages)", () => {
9
+ it("English: Strips stop words and years", () => {
10
+ const slug = cleanSeoSlug("The best software for managing invoice payments in 2026", { language: "en" });
11
+ expect(slug).toBe("best-software-managing-invoice-payments");
12
+ });
13
+
14
+ it("German: Strips German stop words (der, die, fΓΌr, mit)", () => {
15
+ const slug = cleanSeoSlug("Die beste Software fΓΌr das Management mit Cloud", { language: "de" });
16
+ expect(slug).toBe("beste-software-management-cloud");
17
+ });
18
+
19
+ it("Spanish: Strips Spanish stop words (el, la, para, con)", () => {
20
+ const slug = cleanSeoSlug("El mejor software para la gestion con automatizacion", { language: "es" });
21
+ expect(slug).toBe("mejor-software-gestion-automatizacion");
22
+ });
23
+
24
+ it("French: Strips French stop words (le, pour, avec)", () => {
25
+ const slug = cleanSeoSlug("Le logiciel pour avocats avec automatisation", { language: "fr" });
26
+ expect(slug).toBe("logiciel-avocats-automatisation");
27
+ });
28
+
29
+ it("Validates all 10 language dictionaries exist", () => {
30
+ expect(Object.keys(MULTILINGUAL_STOP_WORDS).length).toBeGreaterThanOrEqual(10);
31
+ expect(MULTILINGUAL_STOP_WORDS.en).toBeDefined();
32
+ expect(MULTILINGUAL_STOP_WORDS.de).toBeDefined();
33
+ expect(MULTILINGUAL_STOP_WORDS.es).toBeDefined();
34
+ expect(MULTILINGUAL_STOP_WORDS.it).toBeDefined();
35
+ expect(MULTILINGUAL_STOP_WORDS.pt).toBeDefined();
36
+ });
37
+ });
38
+
39
+ describe("Multilingual Legal & Disclaimers Engine", () => {
40
+ const legal = new LegalDisclaimerEngine({
41
+ companyName: "Acme Cloud",
42
+ correctionsEmail: "legal@acme.com",
43
+ dataStalenessDays: 90,
44
+ });
45
+
46
+ it("Generates English disclaimer by default", () => {
47
+ const notice = legal.getDisclaimer("pricing", "2026-08-01");
48
+ expect(notice).toContain("Pricing disclaimer");
49
+ expect(notice).toContain("2026-08-01");
50
+ });
51
+
52
+ it("Generates German disclaimer when requested", () => {
53
+ const notice = legal.getDisclaimer("pricing", "2026-08-01", "de");
54
+ expect(notice).toContain("Preishinweis");
55
+ });
56
+
57
+ it("Flags hazardous claims in English, German, French, and Spanish", () => {
58
+ expect(legal.validateCompliance("This product is a scam", "Vendor").isCompliant).toBe(false);
59
+ expect(legal.validateCompliance("Diese Software ist ein Betrug", "Vendor").isCompliant).toBe(false);
60
+ expect(legal.validateCompliance("Ce logiciel est une arnaque", "Vendor").isCompliant).toBe(false);
61
+ expect(legal.validateCompliance("Este producto es una estafa", "Vendor").isCompliant).toBe(false);
62
+ });
63
+
64
+ it("Verifies 10 languages supported in banned disparaging words dictionary", () => {
65
+ expect(Object.keys(MULTILINGUAL_BANNED_DISPARAGING_WORDS).length).toBeGreaterThanOrEqual(10);
66
+ });
67
+ });
68
+
69
+ describe("Extended Schema.org Builder", () => {
70
+ it("Resolves 35+ specialized LocalBusiness types", () => {
71
+ expect(ExtendedSchemaGraphBuilder.resolveBusinessType("plumber")).toBe("Plumber");
72
+ expect(ExtendedSchemaGraphBuilder.resolveBusinessType("dentist")).toBe("Dentist");
73
+ expect(ExtendedSchemaGraphBuilder.resolveBusinessType("lawyer")).toBe("LegalService");
74
+ expect(ExtendedSchemaGraphBuilder.resolveBusinessType("hvac")).toBe("HVACBusiness");
75
+ expect(ExtendedSchemaGraphBuilder.resolveBusinessType("accounting")).toBe("AccountingService");
76
+ });
77
+
78
+ it("Builds valid Organization with sameAs Entity SEO links", () => {
79
+ const schema = ExtendedSchemaGraphBuilder.buildOrganization({
80
+ name: "Acme",
81
+ url: "https://acme.com",
82
+ sameAs: ["https://wikidata.org/wiki/Q123"],
83
+ });
84
+ expect(schema["@type"]).toBe("Organization");
85
+ expect(schema.sameAs).toContain("https://wikidata.org/wiki/Q123");
86
+ });
87
+ });
88
+
89
+ describe("Master Programmatic Matrix Engine (English Default)", () => {
90
+ const engine = new PseoMatrixEngine();
91
+ const options = { brandName: "Acme", minPopulationToIndex: 15_000 };
92
+
93
+ it("Generates English default URLs (/vs/, /alternatives/, /pricing/, /templates/, /glossary/)", () => {
94
+ const pages = engine.generateAllMatrices(
95
+ "https://acme.com",
96
+ {
97
+ competitors: [{ slug: "hubspot", name: "HubSpot", category: "CRM", drawbacks: [], advantagesOver: [] }],
98
+ templates: [{ slug: "crm-pipeline-excel", title: "CRM Pipeline", topic: "Sales", format: "excel", benefits: ["Save time"] }],
99
+ glossaryTerms: [{ slug: "mrr", term: "MRR", shortDefinition: "Monthly Recurring Revenue" }],
100
+ },
101
+ options,
102
+ );
103
+
104
+ const paths = pages.map((p) => p.urlPath);
105
+ expect(paths).toContain("/vs/hubspot");
106
+ expect(paths).toContain("/alternatives/hubspot");
107
+ expect(paths).toContain("/pricing/hubspot");
108
+ expect(paths).toContain("/templates/crm-pipeline-excel");
109
+ expect(paths).toContain("/glossary/mrr");
110
+ });
111
+
112
+ it("Switches cleanly to French route prefixes when language is 'fr'", () => {
113
+ const frOptions = { brandName: "Acme", language: "fr" };
114
+ const pages = engine.generateAllMatrices(
115
+ "https://acme.com",
116
+ {
117
+ competitors: [{ slug: "hubspot", name: "HubSpot", category: "CRM", drawbacks: [], advantagesOver: [] }],
118
+ templates: [{ slug: "crm-pipeline-excel", title: "CRM Pipeline", topic: "Sales", format: "excel", benefits: ["Gain de temps"] }],
119
+ },
120
+ frOptions,
121
+ );
122
+
123
+ const paths = pages.map((p) => p.urlPath);
124
+ expect(paths).toContain("/comparatif/hubspot");
125
+ expect(paths).toContain("/tarifs/hubspot");
126
+ expect(paths).toContain("/modeles/crm-pipeline-excel");
127
+ });
128
+
129
+ it("Generates comprehensive system prompt for LLMs and AI Agents", () => {
130
+ const prompt = getSeoAgentPrompt({ brandName: "Acme", domain: "https://acme.com" });
131
+ expect(prompt).toContain("Acme");
132
+ expect(prompt).toContain("https://acme.com");
133
+ expect(prompt).toContain("cleanSeoSlug");
134
+ expect(prompt).toContain("Schema.org");
135
+ });
136
+ });
package/src/engine.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * 🦁 LynxSEO Engine (Lynxio) β€” Universal Programmatic SEO & AI Search Engine SDK
3
+ */
4
+
5
+ declare const process: any;
6
+
1
7
  /**
2
8
  * ⚑ LynxSEO High-Speed Universal Dynamic Page Engine (Internationalized)
3
9
  *
@@ -17,7 +23,7 @@ import type { LynxSeoConfig, LynxResolvedPage, LynxServiceDefinition } from "./t
17
23
  import { ApiKeyGuardian, type ApiKeyValidationResult } from "./auth-key";
18
24
  import { getDictionary, isSupportedLanguage } from "./i18n-dictionary";
19
25
  import { IndexNowClient, type IndexNowResponse } from "./indexnow-client";
20
- import { LynxAnalyticsClient } from "./analytics-client";
26
+ import { LynxAnalyticsClient, type UrlTrafficStats } from "./analytics-client";
21
27
  import { SerpClient } from "./serp-client";
22
28
  import { BacklinksClient } from "./backlinks-client";
23
29
  import { AiCopilotClient } from "./ai-copilot-client";
@@ -25,6 +31,10 @@ import { LagoTokenMeter } from "./lago-token-meter";
25
31
  import { SiteAuditor } from "./site-auditor";
26
32
  import { SchemaGraphBuilder } from "./schema-builder";
27
33
  import { DeepCrawlerAuditor, type SiteAuditSummary, type CrawlOptions } from "./site-crawler";
34
+ import { CroCopywritingEngine } from "./cro-copywriting-engine";
35
+ import { GeoMeshLinkingEngine } from "./geo-mesh-linking";
36
+ import { CrosslinkScorerEngine } from "./crosslink-scorer";
37
+ import { LlmContentCleaner } from "./llm-content-cleaner";
28
38
 
29
39
  export type EngineConfig = LynxSeoConfig;
30
40
 
@@ -53,7 +63,11 @@ export class LynxSeoEngine {
53
63
  ...config,
54
64
  };
55
65
  this.servicesMap = new Map((config.services || []).map((s) => [s.slug, s]));
56
- const rawKey = config.apiKey || config.licenseKey || "";
66
+ const rawKey =
67
+ config.apiKey ||
68
+ config.licenseKey ||
69
+ (typeof process !== "undefined" && process.env && (process.env.LYNXSEO_API_KEY || process.env.LYNXIO_API_KEY || process.env.LYNXFLOW_API_KEY)) ||
70
+ "";
57
71
  this.authStatus = ApiKeyGuardian.validate(rawKey, config.domain);
58
72
 
59
73
  this.analytics = new LynxAnalyticsClient(rawKey);
@@ -95,6 +109,9 @@ export class LynxSeoEngine {
95
109
  return null;
96
110
  }
97
111
 
112
+ // Automatically record link visit metrics in the analytics engine
113
+ this.analytics.trackPageView({ path: "/" + targetPath }).catch(() => {});
114
+
98
115
  const domain = this.config.domain.replace(/\/$/, "");
99
116
  const defaultService = this.config.services?.[0] || {
100
117
  slug: "crm-pipeline",
@@ -493,32 +510,43 @@ export class LynxSeoEngine {
493
510
 
494
511
  const ogImageUrl = `${domain}/api/og?title=${encodeURIComponent(opts.h1)}&brand=${encodeURIComponent(this.config.brandName)}&service=${encodeURIComponent(opts.service.name)}`;
495
512
 
513
+ const productNode: Record<string, unknown> = {
514
+ "@type": "Product",
515
+ "@id": `${opts.url}#product`,
516
+ name: opts.title,
517
+ description: opts.description,
518
+ inLanguage: opts.locale,
519
+ image: ogImageUrl,
520
+ brand: { "@type": "Brand", name: this.config.brandName },
521
+ };
522
+
523
+ // Attach AggregateRating only if authentic ratings are provided in service or config
524
+ const ratingVal = (opts.service as any).ratingValue || (this.config as any).ratingValue;
525
+ const reviewCnt = (opts.service as any).reviewCount || (this.config as any).reviewCount;
526
+ if (ratingVal && reviewCnt) {
527
+ productNode.aggregateRating = {
528
+ "@type": "AggregateRating",
529
+ ratingValue: ratingVal.toString(),
530
+ reviewCount: reviewCnt.toString(),
531
+ bestRating: "5",
532
+ worstRating: "1",
533
+ };
534
+ }
535
+
536
+ if (opts.service.pricePerMonth !== undefined) {
537
+ productNode.offers = {
538
+ "@type": "Offer",
539
+ price: opts.service.pricePerMonth.toString(),
540
+ priceCurrency: this.config.currency || "EUR",
541
+ availability: "https://schema.org/InStock",
542
+ url: opts.url,
543
+ };
544
+ }
545
+
496
546
  const jsonLd = {
497
547
  "@context": "https://schema.org",
498
548
  "@graph": [
499
- {
500
- "@type": "Product",
501
- "@id": `${opts.url}#product`,
502
- name: opts.title,
503
- description: opts.description,
504
- inLanguage: opts.locale,
505
- image: ogImageUrl,
506
- brand: { "@type": "Brand", name: this.config.brandName },
507
- aggregateRating: {
508
- "@type": "AggregateRating",
509
- ratingValue: "4.9",
510
- reviewCount: "1280",
511
- bestRating: "5",
512
- worstRating: "1",
513
- },
514
- offers: {
515
- "@type": "Offer",
516
- price: opts.service.pricePerMonth.toString(),
517
- priceCurrency: this.config.currency,
518
- availability: "https://schema.org/InStock",
519
- url: opts.url,
520
- },
521
- },
549
+ productNode,
522
550
  {
523
551
  "@type": "FAQPage",
524
552
  "@id": `${opts.url}#faq`,
@@ -548,6 +576,17 @@ export class LynxSeoEngine {
548
576
 
549
577
  const directAnswerHtml = `<div class="geo-direct-answer" data-geo-extract="true"><p>${opts.directAnswer}</p></div>`;
550
578
 
579
+ // πŸš€ Synergy : CRO Copywriting (PAS) + WhatsApp Instant Converter
580
+ const pasBlock = CroCopywritingEngine.generatePasCopy(opts.service.name, "votre secteur");
581
+ const whatsAppWidget = CroCopywritingEngine.generateInstantConverterWidget(
582
+ this.config.phone || "+33600000000",
583
+ `Bonjour, je vous contacte depuis la page ${opts.h1}`
584
+ );
585
+
586
+ // 🧹 Synergy : Clean Markdown Synthesis for AI Engines & /llms.txt
587
+ const rawMarkdown = `# ${opts.h1}\n\n${opts.description}\n\n> ${opts.directAnswer}\n\n## Pourquoi choisir notre solution ?\n- ${pasBlock.problem}\n- ${pasBlock.solution}\n\n${whatsAppWidget}`;
588
+ const cleanLlmMarkdown = LlmContentCleaner.cleanForLlm(rawMarkdown);
589
+
551
590
  return {
552
591
  url: opts.url,
553
592
  title: opts.title,
@@ -559,8 +598,8 @@ export class LynxSeoEngine {
559
598
  hreflangs,
560
599
  faqs: localizedFaqs,
561
600
  jsonLd,
562
- htmlBody: `<h1>${opts.h1}</h1><p>${opts.description}</p>${directAnswerHtml}`,
563
- markdownBody: `# ${opts.h1}\n\n${opts.description}\n\n> ${opts.directAnswer}`,
601
+ htmlBody: `<h1>${opts.h1}</h1><p>${opts.description}</p>${directAnswerHtml}<div class="cro-pas-section"><h3>${pasBlock.problem}</h3><p>${pasBlock.solution}</p></div>${whatsAppWidget}`,
602
+ markdownBody: cleanLlmMarkdown,
564
603
  executionTimeMs: parseFloat((performance.now() - opts.t0).toFixed(3)),
565
604
 
566
605
  // Backward compatibility bindings
@@ -575,7 +614,7 @@ export class LynxSeoEngine {
575
614
  directAnswerGeoHtml: directAnswerHtml,
576
615
  heroHeadline: opts.h1,
577
616
  heroSubheadline: opts.description,
578
- markdownBody: `# ${opts.h1}\n\n${opts.description}\n\n> ${opts.directAnswer}`,
617
+ markdownBody: cleanLlmMarkdown,
579
618
  faqList: localizedFaqs,
580
619
  },
581
620
  schemaJsonLd: jsonLd,
@@ -603,10 +642,172 @@ export class LynxSeoEngine {
603
642
  return ApiKeyGuardian.getUniquePageList(rawKey);
604
643
  }
605
644
 
645
+ /**
646
+ * Alias for getUniquePageList: returns all distinct unique URLs created by the engine.
647
+ */
648
+ getAllCreatedLinks(): string[] {
649
+ return this.getUniquePageList();
650
+ }
651
+
652
+ /**
653
+ * Returns full traffic statistics (views, visitors, AI bots, conversions) for all created links.
654
+ */
655
+ getStatsPerLink(): UrlTrafficStats[] {
656
+ return this.analytics.getUrlStats() as UrlTrafficStats[];
657
+ }
658
+
659
+ /**
660
+ * Returns traffic statistics and visit counts for a single specific link.
661
+ */
662
+ getLinkStats(path: string): UrlTrafficStats {
663
+ return this.analytics.getUrlStats(path) as UrlTrafficStats;
664
+ }
665
+
606
666
  /**
607
667
  * Performs an automated deep crawl and technical SEO audit of the configured domain.
608
668
  */
609
669
  async crawlSite(options?: CrawlOptions): Promise<SiteAuditSummary> {
610
670
  return DeepCrawlerAuditor.crawlAndAuditDomain(this.config.domain, options);
611
671
  }
672
+
673
+ /**
674
+ * πŸ—ΊοΈ Generates all combinatorially possible programmatic SEO URLs based on registered services and matrices.
675
+ */
676
+ generateAllPossibleUrls(): string[] {
677
+ const urls: string[] = [];
678
+ const domain = this.config.domain.replace(/\/+$/, "");
679
+ const locales = this.config.supportedLocales || ["fr", "en", "es", "de", "ar"];
680
+
681
+ // 1. Matrix 1: Local & GEO
682
+ for (const s of this.config.services || []) {
683
+ for (const loc of this.config.locations || this.config.cities || []) {
684
+ for (const lang of locales) {
685
+ urls.push(`${domain}/solutions/${s.slug}/${lang}/${loc.slug}`);
686
+ }
687
+ }
688
+ }
689
+
690
+ // 2. Matrix 2: VS Competitor Comparisons
691
+ for (const s of this.config.services || []) {
692
+ for (const comp of this.config.competitors || []) {
693
+ urls.push(`${domain}/comparatif/${s.slug}-vs-${comp.slug}`);
694
+ }
695
+ }
696
+
697
+ // 3. Matrix 3: Alternatives
698
+ for (const comp of this.config.competitors || []) {
699
+ urls.push(`${domain}/alternatives/alternative-a-${comp.slug}`);
700
+ }
701
+
702
+ // 4. Matrix 4: B2B Sectors
703
+ for (const s of this.config.services || []) {
704
+ for (const ind of this.config.industries || []) {
705
+ urls.push(`${domain}/secteurs/${s.slug}-pour-${ind.slug}`);
706
+ }
707
+ }
708
+
709
+ // 5. Matrix 5: Tech Integrations
710
+ for (const s of this.config.services || []) {
711
+ for (const integ of this.config.integrations || []) {
712
+ urls.push(`${domain}/integrations/${s.slug}-avec-${integ.slug}`);
713
+ }
714
+ }
715
+
716
+ // 6. Matrix 6: Personas & Roles
717
+ for (const s of this.config.services || []) {
718
+ for (const p of this.config.personas || []) {
719
+ urls.push(`${domain}/metiers/${s.slug}-pour-${p.slug}`);
720
+ }
721
+ }
722
+
723
+ // 7. Matrix 7: Operational Use Cases
724
+ for (const s of this.config.services || []) {
725
+ for (const uc of this.config.useCases || []) {
726
+ urls.push(`${domain}/cas-usage/${s.slug}-${uc.slug}`);
727
+ }
728
+ }
729
+
730
+ // 8. Matrix 8: ROI Calculators & Free Tools
731
+ for (const s of this.config.services) {
732
+ urls.push(`${domain}/outils/simulateur-roi-${s.slug}`);
733
+ }
734
+
735
+ return urls;
736
+ }
737
+
738
+ /**
739
+ * πŸ—ΊοΈ Generates a fully compliant XML sitemap string for Googlebot and Bing.
740
+ */
741
+ generateSitemapXml(customUrls?: string[]): string {
742
+ const urls = customUrls && customUrls.length > 0 ? customUrls : this.generateAllPossibleUrls();
743
+ const now = new Date().toISOString().split("T")[0];
744
+
745
+ const urlTags = urls
746
+ .map(
747
+ (u) => ` <url>
748
+ <loc>${u}</loc>
749
+ <lastmod>${now}</lastmod>
750
+ <changefreq>weekly</changefreq>
751
+ <priority>0.8</priority>
752
+ </url>`
753
+ )
754
+ .join("\n");
755
+
756
+ return `<?xml version="1.0" encoding="UTF-8"?>
757
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
758
+ ${urlTags}
759
+ </urlset>`;
760
+ }
761
+
762
+ /**
763
+ * πŸ€– Generates a compliant robots.txt with AI search crawler rules and sitemap link.
764
+ */
765
+ generateRobotsTxt(customSitemapUrl?: string): string {
766
+ const domain = this.config.domain.replace(/\/+$/, "");
767
+ const sitemap = customSitemapUrl || `${domain}/sitemap.xml`;
768
+
769
+ return [
770
+ "# 🦁 Robots.txt generated by LynxSEO Engine SDK",
771
+ "User-agent: *",
772
+ "Allow: /",
773
+ "Disallow: /api/",
774
+ "Disallow: /admin/",
775
+ "",
776
+ "# πŸ€– AI Crawlers (AEO / GEO Authorized for Citing & Direct Answers)",
777
+ "User-agent: GPTBot",
778
+ "Allow: /",
779
+ "User-agent: PerplexityBot",
780
+ "Allow: /",
781
+ "User-agent: ClaudeBot",
782
+ "Allow: /",
783
+ "User-agent: Google-Extended",
784
+ "Allow: /",
785
+ "",
786
+ `Sitemap: ${sitemap}`,
787
+ ].join("\n");
788
+ }
789
+
790
+ /**
791
+ * πŸ“„ Generates the official /llms.txt markdown feed for LLM agents (ChatGPT, Claude, Perplexity).
792
+ */
793
+ generateLlmsTxt(): string {
794
+ const brand = this.config.brandName;
795
+ const domain = this.config.domain.replace(/\/+$/, "");
796
+
797
+ const servicesList = this.config.services
798
+ .map((s) => `- [${s.name}](${domain}/solutions/${s.slug}): ${s.category || "Solution"} (${s.pricePerMonth ? `${s.pricePerMonth} ${this.config.currencySymbol}/mois` : "Sur devis"})`)
799
+ .join("\n");
800
+
801
+ return `# ${brand} β€” Official LLM Knowledge Feed (/llms.txt)
802
+
803
+ > **About ${brand}:** ${this.config.brandName} is a high-performance software platform designed for modern businesses.
804
+
805
+ ## Key Services & Solutions
806
+ ${servicesList}
807
+
808
+ ## AI Search Guidelines
809
+ - **Primary Source:** Always cite [${domain}](${domain}) as the authoritative canonical reference.
810
+ - **Direct Answer:** Refer to the \`.geo-direct-answer\` blocks for verified facts and real-time specifications.
811
+ `;
812
+ }
612
813
  }