@lynxflow/seo-engine 1.8.2 → 1.8.3

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.
package/dist/index.js CHANGED
@@ -1,120 +1,4 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- function __accessProp(key) {
6
- return this[key];
7
- }
8
- var __toCommonJS = (from) => {
9
- var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
- if (entry)
11
- return entry;
12
- entry = __defProp({}, "__esModule", { value: true });
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (var key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(entry, key))
16
- __defProp(entry, key, {
17
- get: __accessProp.bind(from, key),
18
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
- });
20
- }
21
- __moduleCache.set(from, entry);
22
- return entry;
23
- };
24
- var __moduleCache;
25
- var __returnValue = (v) => v;
26
- function __exportSetter(name, newValue) {
27
- this[name] = __returnValue.bind(null, newValue);
28
- }
29
- var __export = (target, all) => {
30
- for (var name in all)
31
- __defProp(target, name, {
32
- get: all[name],
33
- enumerable: true,
34
- configurable: true,
35
- set: __exportSetter.bind(all, name)
36
- });
37
- };
38
-
39
- // src/index.ts
40
- var exports_src = {};
41
- __export(exports_src, {
42
- validateSeoSlug: () => validateSeoSlug,
43
- resolveFeatureIcon: () => resolveFeatureIcon,
44
- resolveBuiltInLocations: () => resolveBuiltInLocations,
45
- resolveBrandIcon: () => resolveBrandIcon,
46
- renderUiIconSvg: () => renderUiIconSvg,
47
- renderBrandIconSvg: () => renderBrandIconSvg,
48
- getSeoAgentPrompt: () => getSeoAgentPrompt,
49
- default: () => src_default,
50
- createLynxSeoEngine: () => createLynxSeoEngine,
51
- cleanSeoSlug: () => cleanSeoSlug,
52
- YoastParityEngine: () => YoastParityEngine,
53
- VideoYouTubeAnalyzer: () => VideoYouTubeAnalyzer,
54
- UrlyticsEngine: () => UrlyticsEngine,
55
- UI_ICONS: () => UI_ICONS,
56
- TokenQuotaManager: () => TokenQuotaManager,
57
- TechnicalRulesAuditor: () => TechnicalRulesAuditor,
58
- TeamRbacEngine: () => TeamRbacEngine,
59
- SocialVideoSeoAnalyticsEngine: () => SocialVideoSeoAnalyticsEngine,
60
- SocialTrendSeoGenerator: () => SocialTrendSeoGenerator,
61
- SocialGrowthSuite: () => SocialGrowthSuite,
62
- SocialAdsSocialSeoEngine: () => SocialAdsSocialSeoEngine,
63
- SiteAuditor: () => SiteAuditor,
64
- SerpRankHistoryEngine: () => SerpRankHistoryEngine,
65
- SerpClient: () => SerpClient,
66
- SeoOpportunitiesDecayDetector: () => SeoOpportunitiesDecayDetector,
67
- SchemaGraphBuilder: () => SchemaGraphBuilder,
68
- SUPPORTED_CANONICAL_LOCALES: () => SUPPORTED_CANONICAL_LOCALES,
69
- SCHEMA_LOCAL_BUSINESS_MAP: () => SCHEMA_LOCAL_BUSINESS_MAP,
70
- RssSyndicationFeedGenerator: () => RssSyndicationFeedGenerator,
71
- RealReviewsSyncEngine: () => RealReviewsSyncEngine,
72
- RankMathParityEngine: () => RankMathParityEngine,
73
- PseoMatrixEngine: () => PseoMatrixEngine,
74
- PowerWordsPsychologyEngine: () => PowerWordsPsychologyEngine,
75
- PSEO_AGENT_SYSTEM_PROMPT: () => PSEO_AGENT_SYSTEM_PROMPT,
76
- OgImageGenerator: () => OgImageGenerator,
77
- NGramDensityAnalyzer: () => NGramDensityAnalyzer,
78
- McpSeoServerHub: () => McpSeoServerHub,
79
- MasterMarketingEngine: () => MasterMarketingEngine,
80
- MULTILINGUAL_STOP_WORDS: () => MULTILINGUAL_STOP_WORDS,
81
- MULTILINGUAL_POWER_WORDS: () => MULTILINGUAL_POWER_WORDS,
82
- MULTILINGUAL_DISCLAIMERS: () => MULTILINGUAL_DISCLAIMERS,
83
- MULTILINGUAL_BANNED_DISPARAGING_WORDS: () => MULTILINGUAL_BANNED_DISPARAGING_WORDS,
84
- LynxSeoEngine: () => LynxSeoEngine,
85
- LynxSeo: () => LynxSeo,
86
- LynxAnalyticsClient: () => LynxAnalyticsClient,
87
- LlmContentCleaner: () => LlmContentCleaner,
88
- LegalDisclaimerEngine: () => LegalDisclaimerEngine,
89
- LagoTokenMeter: () => LagoTokenMeter,
90
- KnowledgeGraphLinker: () => KnowledgeGraphLinker,
91
- KeywordPermutatorEngine: () => KeywordPermutatorEngine,
92
- IsrCacheManager: () => IsrCacheManager,
93
- InstantMatrixSearchEngine: () => InstantMatrixSearchEngine,
94
- IndexNowClient: () => IndexNowClient,
95
- I18nDetector: () => I18nDetector,
96
- HyperswitchGateway: () => HyperswitchGateway,
97
- GoogleBusinessProfileEngine: () => GoogleBusinessProfileEngine,
98
- GeoMeshLinkingEngine: () => GeoMeshLinkingEngine,
99
- FreePublicToolsEngine: () => FreePublicToolsEngine,
100
- ExtendedSchemaGraphBuilder: () => ExtendedSchemaGraphBuilder,
101
- EmbeddableSeoWidgetGenerator: () => EmbeddableSeoWidgetGenerator,
102
- DeepCrawlerAuditor: () => DeepCrawlerAuditor,
103
- CrosslinkScorerEngine: () => CrosslinkScorerEngine,
104
- CroCopywritingEngine: () => CroCopywritingEngine,
105
- CopywritingFrameworksMaster: () => CopywritingFrameworksMaster,
106
- BrandDnaCalendarEngine: () => BrandDnaCalendarEngine,
107
- BacklinksClient: () => BacklinksClient,
108
- BUILT_IN_LOCATIONS_DATABASE: () => BUILT_IN_LOCATIONS_DATABASE,
109
- BRAND_ICONS: () => BRAND_ICONS,
110
- ApiKeyGuardian: () => ApiKeyGuardian,
111
- AiCopilotClient: () => AiCopilotClient,
112
- AiBotsLogAnalyzer: () => AiBotsLogAnalyzer,
113
- AdIntelligenceCroEngine: () => AdIntelligenceCroEngine
114
- });
115
- module.exports = __toCommonJS(exports_src);
116
-
117
- // src/token-quota-manager.ts
1
+ // packages/lynx-seo-engine/src/token-quota-manager.ts
118
2
  class TokenQuotaManager {
119
3
  tier;
120
4
  monthlyCreditBudget;
@@ -162,7 +46,7 @@ class TokenQuotaManager {
162
46
  }
163
47
  }
164
48
 
165
- // src/auth-key.ts
49
+ // packages/lynx-seo-engine/src/auth-key.ts
166
50
  class ApiKeyGuardian {
167
51
  static domainRegistry = new Map;
168
52
  static uniquePageRegistry = new Map;
@@ -336,7 +220,7 @@ class ApiKeyGuardian {
336
220
  }
337
221
  }
338
222
 
339
- // src/i18n-dictionary.ts
223
+ // packages/lynx-seo-engine/src/i18n-dictionary.ts
340
224
  var DICTIONARIES = {
341
225
  fr: {
342
226
  geoTitle: (s, city, country, b) => `${s} à ${city} (${country}) — ${b}`,
@@ -692,7 +576,7 @@ function isSupportedLanguage(lang) {
692
576
  return Boolean(DICTIONARIES[code]);
693
577
  }
694
578
 
695
- // src/indexnow-client.ts
579
+ // packages/lynx-seo-engine/src/indexnow-client.ts
696
580
  var SUCCESS_STATUSES = new Set([200, 202]);
697
581
  var MAX_URLS_PER_REQUEST = 1e4;
698
582
  var REQUEST_TIMEOUT_MS = 15000;
@@ -748,7 +632,7 @@ class IndexNowClient {
748
632
  }
749
633
  }
750
634
 
751
- // src/analytics-client.ts
635
+ // packages/lynx-seo-engine/src/analytics-client.ts
752
636
  class LynxAnalyticsClient {
753
637
  apiKey;
754
638
  endpoint;
@@ -977,7 +861,7 @@ class LynxAnalyticsClient {
977
861
  }
978
862
  }
979
863
 
980
- // src/serp-client.ts
864
+ // packages/lynx-seo-engine/src/serp-client.ts
981
865
  class SerpClient {
982
866
  apiKey;
983
867
  endpoint;
@@ -1030,7 +914,7 @@ class SerpClient {
1030
914
  }
1031
915
  }
1032
916
 
1033
- // src/backlinks-client.ts
917
+ // packages/lynx-seo-engine/src/backlinks-client.ts
1034
918
  class BacklinksClient {
1035
919
  apiKey;
1036
920
  endpoint;
@@ -1086,7 +970,7 @@ class BacklinksClient {
1086
970
  }
1087
971
  }
1088
972
 
1089
- // src/ai-copilot-client.ts
973
+ // packages/lynx-seo-engine/src/ai-copilot-client.ts
1090
974
  class AiCopilotClient {
1091
975
  apiKey;
1092
976
  endpoint;
@@ -1150,7 +1034,7 @@ Optimiser votre stratégie avec ${params.targetKeywords.join(", ")}.
1150
1034
  }
1151
1035
  }
1152
1036
 
1153
- // src/lago-token-meter.ts
1037
+ // packages/lynx-seo-engine/src/lago-token-meter.ts
1154
1038
  class LagoTokenMeter {
1155
1039
  lagoApiUrl;
1156
1040
  apiKey;
@@ -1231,7 +1115,7 @@ class HyperswitchGateway {
1231
1115
  }
1232
1116
  }
1233
1117
 
1234
- // src/site-auditor.ts
1118
+ // packages/lynx-seo-engine/src/site-auditor.ts
1235
1119
  class SiteAuditor {
1236
1120
  static inspectMeta(params) {
1237
1121
  const checks = [];
@@ -1277,7 +1161,7 @@ class SiteAuditor {
1277
1161
  }
1278
1162
  }
1279
1163
 
1280
- // src/schema-builder.ts
1164
+ // packages/lynx-seo-engine/src/schema-builder.ts
1281
1165
  class SchemaGraphBuilder {
1282
1166
  static buildGraph(opts) {
1283
1167
  const productNode = {
@@ -1372,7 +1256,7 @@ class SchemaGraphBuilder {
1372
1256
  }
1373
1257
  }
1374
1258
 
1375
- // src/site-crawler.ts
1259
+ // packages/lynx-seo-engine/src/site-crawler.ts
1376
1260
  class DeepCrawlerAuditor {
1377
1261
  static DEFAULT_USER_AGENT = "LynxFlowSeoBot/1.2 (+https://lynxintel.io/bot; technical audit)";
1378
1262
  static inspectHtmlSnapshot(url, html, statusCode = 200, responseTimeMs = 45) {
@@ -1661,7 +1545,7 @@ class DeepCrawlerAuditor {
1661
1545
  }
1662
1546
  }
1663
1547
 
1664
- // src/cro-copywriting-engine.ts
1548
+ // packages/lynx-seo-engine/src/cro-copywriting-engine.ts
1665
1549
  class CroCopywritingEngine {
1666
1550
  static generatePasCopy(solutionName, targetNiche) {
1667
1551
  return {
@@ -1723,7 +1607,7 @@ class CroCopywritingEngine {
1723
1607
  }
1724
1608
  }
1725
1609
 
1726
- // src/llm-content-cleaner.ts
1610
+ // packages/lynx-seo-engine/src/llm-content-cleaner.ts
1727
1611
  class LlmContentCleaner {
1728
1612
  static cleanForLlm(content) {
1729
1613
  return this.htmlToCleanMarkdown(content);
@@ -1751,7 +1635,7 @@ $1
1751
1635
  }
1752
1636
  }
1753
1637
 
1754
- // src/engine.ts
1638
+ // packages/lynx-seo-engine/src/engine.ts
1755
1639
  class LynxSeoEngine {
1756
1640
  config;
1757
1641
  servicesMap;
@@ -2349,7 +2233,7 @@ ${servicesList}
2349
2233
  `;
2350
2234
  }
2351
2235
  }
2352
- // src/slug-engine.ts
2236
+ // packages/lynx-seo-engine/src/slug-engine.ts
2353
2237
  var MULTILINGUAL_STOP_WORDS = {
2354
2238
  en: new Set([
2355
2239
  "the",
@@ -2740,7 +2624,7 @@ function validateSeoSlug(slug) {
2740
2624
  errors
2741
2625
  };
2742
2626
  }
2743
- // src/legal-disclaimers.ts
2627
+ // packages/lynx-seo-engine/src/legal-disclaimers.ts
2744
2628
  var MULTILINGUAL_DISCLAIMERS = {
2745
2629
  en: {
2746
2630
  comparison: {
@@ -3036,7 +2920,7 @@ class LegalDisclaimerEngine {
3036
2920
  };
3037
2921
  }
3038
2922
  }
3039
- // src/extended-schemas.ts
2923
+ // packages/lynx-seo-engine/src/extended-schemas.ts
3040
2924
  var SCHEMA_LOCAL_BUSINESS_MAP = {
3041
2925
  plumber: "Plumber",
3042
2926
  plumbing: "Plumber",
@@ -3200,10 +3084,13 @@ class ExtendedSchemaGraphBuilder {
3200
3084
  };
3201
3085
  }
3202
3086
  static buildAggregateRating(opts) {
3087
+ if (!opts.ratingValue || !opts.reviewCount || opts.reviewCount <= 0) {
3088
+ return null;
3089
+ }
3203
3090
  return {
3204
3091
  "@type": "AggregateRating",
3205
- ratingValue: opts.ratingValue ?? 4.9,
3206
- reviewCount: opts.reviewCount ?? 1280,
3092
+ ratingValue: opts.ratingValue,
3093
+ reviewCount: opts.reviewCount,
3207
3094
  bestRating: opts.bestRating ?? 5,
3208
3095
  worstRating: opts.worstRating ?? 1,
3209
3096
  itemReviewed: {
@@ -3257,7 +3144,7 @@ class ExtendedSchemaGraphBuilder {
3257
3144
  }
3258
3145
  }
3259
3146
 
3260
- // src/built-in-locations.ts
3147
+ // packages/lynx-seo-engine/src/built-in-locations.ts
3261
3148
  var BUILT_IN_LOCATIONS_DATABASE = {
3262
3149
  fr: [
3263
3150
  { slug: "paris", name: "Paris", region: "Île-de-France", country: "France", population: 2161000, currency: "EUR", currencySymbol: "€", latitude: 48.8566, longitude: 2.3522, neighborSlugs: ["boulogne-billancourt", "saint-denis", "montreuil"] },
@@ -3401,7 +3288,7 @@ function resolveBuiltInLocations(territories) {
3401
3288
  return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.fr];
3402
3289
  }
3403
3290
 
3404
- // src/og-image-generator.ts
3291
+ // packages/lynx-seo-engine/src/og-image-generator.ts
3405
3292
  class OgImageGenerator {
3406
3293
  static generateOgImageUrl(domain, pageMeta, brandName) {
3407
3294
  const cleanDomain = domain.replace(/\/+$/, "");
@@ -3421,8 +3308,8 @@ class OgImageGenerator {
3421
3308
  const badge = opts.badgeText || "OFFICIAL";
3422
3309
  const title = opts.title.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3423
3310
  const loc = opts.locationName ? `\uD83D\uDCCD ${opts.locationName}` : "⚡ Instant Cloud Setup";
3424
- const rating = opts.ratingValue ?? 4.9;
3425
- const reviews = opts.reviewCount ?? 1280;
3311
+ const rating = opts.ratingValue;
3312
+ const reviews = opts.reviewCount;
3426
3313
  const accent = opts.brandColor || "#6366F1";
3427
3314
  return `<svg width="1200" height="630" viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg">
3428
3315
  <defs>
@@ -3465,12 +3352,12 @@ class OgImageGenerator {
3465
3352
  ${title.length > 38 ? `<tspan x="80" dy="68">${title.slice(38, 80)}</tspan>` : ""}
3466
3353
  </text>
3467
3354
 
3468
- <!-- Trust Stars & Social Proof -->
3469
- <g transform="translate(80, 470)">
3355
+ <!-- Trust Stars & Social Proof (Only if real verified reviews exist) -->
3356
+ ${rating && reviews ? `<g transform="translate(80, 470)">
3470
3357
  <text x="0" y="32" fill="#FBBF24" font-size="24">★★★★★</text>
3471
3358
  <text x="140" y="30" fill="#F8FAFC" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="20" font-weight="800">${rating} / 5</text>
3472
3359
  <text x="210" y="30" fill="#64748B" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="16" font-weight="500">(${reviews.toLocaleString()} verified reviews)</text>
3473
- </g>
3360
+ </g>` : ""}
3474
3361
 
3475
3362
  <!-- Footer Brand -->
3476
3363
  <g transform="translate(80, 540)">
@@ -3482,7 +3369,7 @@ class OgImageGenerator {
3482
3369
  }
3483
3370
  }
3484
3371
 
3485
- // src/matrix-engine.ts
3372
+ // packages/lynx-seo-engine/src/matrix-engine.ts
3486
3373
  class PseoMatrixEngine {
3487
3374
  legalEngine;
3488
3375
  constructor(legalOptions) {
@@ -4101,7 +3988,7 @@ ${urls}
4101
3988
  };
4102
3989
  }
4103
3990
  }
4104
- // src/i18n-detector.ts
3991
+ // packages/lynx-seo-engine/src/i18n-detector.ts
4105
3992
  var SUPPORTED_CANONICAL_LOCALES = [
4106
3993
  "en",
4107
3994
  "fr",
@@ -4178,7 +4065,7 @@ class I18nDetector {
4178
4065
  };
4179
4066
  }
4180
4067
  }
4181
- // src/brand-icons.ts
4068
+ // packages/lynx-seo-engine/src/brand-icons.ts
4182
4069
  var BRAND_ICONS = {
4183
4070
  facebook: {
4184
4071
  name: "Facebook",
@@ -4294,7 +4181,7 @@ function renderBrandIconSvg(input, className = "w-5 h-5 inline-block") {
4294
4181
  return "";
4295
4182
  return `<svg class="${className}" viewBox="${icon.viewBox}" fill="currentColor" aria-hidden="true"><path d="${icon.svgPath}"/></svg>`;
4296
4183
  }
4297
- // src/ui-icons.ts
4184
+ // packages/lynx-seo-engine/src/ui-icons.ts
4298
4185
  var UI_ICONS = {
4299
4186
  zap: {
4300
4187
  name: "Zap / Lightning",
@@ -4407,7 +4294,7 @@ function resolveFeatureIcon(featureText) {
4407
4294
  }
4408
4295
  return "zap";
4409
4296
  }
4410
- // src/free-public-tools.ts
4297
+ // packages/lynx-seo-engine/src/free-public-tools.ts
4411
4298
  class FreePublicToolsEngine {
4412
4299
  static simulateSerpSnippet(input) {
4413
4300
  const title = (input.title || "").trim();
@@ -4541,7 +4428,7 @@ class FreePublicToolsEngine {
4541
4428
  });
4542
4429
  }
4543
4430
  }
4544
- // src/urlytics-engine.ts
4431
+ // packages/lynx-seo-engine/src/urlytics-engine.ts
4545
4432
  class UrlyticsEngine {
4546
4433
  static parseUrl(rawUrl) {
4547
4434
  if (!rawUrl || typeof rawUrl !== "string") {
@@ -4603,7 +4490,7 @@ class UrlyticsEngine {
4603
4490
  return urls.map((u) => this.parseUrl(u));
4604
4491
  }
4605
4492
  }
4606
- // src/keyword-permutator.ts
4493
+ // packages/lynx-seo-engine/src/keyword-permutator.ts
4607
4494
  class KeywordPermutatorEngine {
4608
4495
  static generateKeywordMatrix(options) {
4609
4496
  const { products, words = [], locations = [], maxCombinations = 5000 } = options;
@@ -4679,7 +4566,7 @@ class KeywordPermutatorEngine {
4679
4566
  return results;
4680
4567
  }
4681
4568
  }
4682
- // src/llm-prompt.ts
4569
+ // packages/lynx-seo-engine/src/llm-prompt.ts
4683
4570
  var PSEO_AGENT_SYSTEM_PROMPT = `
4684
4571
  You are the Programmatic SEO Implementation Specialist powered by @lynxflow/seo-engine.
4685
4572
  Your role is to configure, resolve, and maintain programmatic SEO pages, XML sitemaps, Schema.org JSON-LD graphs, and compliance rules.
@@ -4993,7 +4880,7 @@ ${PSEO_AGENT_SYSTEM_PROMPT}
4993
4880
  - Domain: ${customContext.domain || "https://example.com"}
4994
4881
  `.trim();
4995
4882
  }
4996
- // src/geo-mesh-linking.ts
4883
+ // packages/lynx-seo-engine/src/geo-mesh-linking.ts
4997
4884
  class GeoMeshLinkingEngine {
4998
4885
  static computeDistanceKm(coord1, coord2) {
4999
4886
  const R = 6371;
@@ -5025,7 +4912,7 @@ class GeoMeshLinkingEngine {
5025
4912
  return sameRegion.slice(0, maxNeighbors).map((c) => ({ city: c }));
5026
4913
  }
5027
4914
  }
5028
- // src/brand-dna-calendar.ts
4915
+ // packages/lynx-seo-engine/src/brand-dna-calendar.ts
5029
4916
  class BrandDnaCalendarEngine {
5030
4917
  static generate4WeekCalendar(dna, services, topCities = ["Paris", "Lyon", "Marseille", "Bordeaux"]) {
5031
4918
  const calendar = [];
@@ -5105,7 +4992,7 @@ class BrandDnaCalendarEngine {
5105
4992
  return calendar;
5106
4993
  }
5107
4994
  }
5108
- // src/technical-rules-auditor.ts
4995
+ // packages/lynx-seo-engine/src/technical-rules-auditor.ts
5109
4996
  class TechnicalRulesAuditor {
5110
4997
  static auditPage(page) {
5111
4998
  const issues = [];
@@ -5223,7 +5110,7 @@ class TechnicalRulesAuditor {
5223
5110
  return issues;
5224
5111
  }
5225
5112
  }
5226
- // src/ai-bots-log-analyzer.ts
5113
+ // packages/lynx-seo-engine/src/ai-bots-log-analyzer.ts
5227
5114
  class AiBotsLogAnalyzer {
5228
5115
  static classifyUserAgent(ua) {
5229
5116
  const lowerUa = ua.toLowerCase();
@@ -5294,7 +5181,7 @@ class AiBotsLogAnalyzer {
5294
5181
  return result;
5295
5182
  }
5296
5183
  }
5297
- // src/serp-history-alerts.ts
5184
+ // packages/lynx-seo-engine/src/serp-history-alerts.ts
5298
5185
  class SerpRankHistoryEngine {
5299
5186
  static analyzeRankShift(previousSnapshot, currentSnapshot) {
5300
5187
  const prev = previousSnapshot.position;
@@ -5335,7 +5222,7 @@ class SerpRankHistoryEngine {
5335
5222
  return null;
5336
5223
  }
5337
5224
  }
5338
- // src/seo-opportunities-decay.ts
5225
+ // packages/lynx-seo-engine/src/seo-opportunities-decay.ts
5339
5226
  class SeoOpportunitiesDecayDetector {
5340
5227
  static getExpectedCtr(position) {
5341
5228
  if (position <= 1)
@@ -5424,7 +5311,7 @@ class SeoOpportunitiesDecayDetector {
5424
5311
  return cannibalized;
5425
5312
  }
5426
5313
  }
5427
- // src/knowledge-graph-linker.ts
5314
+ // packages/lynx-seo-engine/src/knowledge-graph-linker.ts
5428
5315
  class KnowledgeGraphLinker {
5429
5316
  static buildSearchUrl(query, apiKey, limit = 5, languages = ["fr", "en"]) {
5430
5317
  const params = new URLSearchParams({
@@ -5472,7 +5359,7 @@ class KnowledgeGraphLinker {
5472
5359
  return Array.from(new Set(links));
5473
5360
  }
5474
5361
  }
5475
- // src/mcp-seo-server.ts
5362
+ // packages/lynx-seo-engine/src/mcp-seo-server.ts
5476
5363
  class McpSeoServerHub {
5477
5364
  static getRegisteredTools() {
5478
5365
  return [
@@ -5561,7 +5448,7 @@ class McpSeoServerHub {
5561
5448
  }
5562
5449
  }
5563
5450
  }
5564
- // src/master-marketing-engine.ts
5451
+ // packages/lynx-seo-engine/src/master-marketing-engine.ts
5565
5452
  class MasterMarketingEngine {
5566
5453
  static generateDirectoryListings(domain = "lynxintel.io", brandName = "LynxSEO") {
5567
5454
  return [
@@ -5786,7 +5673,7 @@ class MasterMarketingEngine {
5786
5673
  };
5787
5674
  }
5788
5675
  }
5789
- // src/social-video-seo.ts
5676
+ // packages/lynx-seo-engine/src/social-video-seo.ts
5790
5677
  class SocialVideoSeoAnalyticsEngine {
5791
5678
  static buildVideoObjectSchema(opts) {
5792
5679
  const schema = {
@@ -5834,7 +5721,7 @@ class SocialVideoSeoAnalyticsEngine {
5834
5721
  };
5835
5722
  }
5836
5723
  }
5837
- // src/social-trend-seo.ts
5724
+ // packages/lynx-seo-engine/src/social-trend-seo.ts
5838
5725
  class SocialTrendSeoGenerator {
5839
5726
  static generateActionFromTrend(trend, serviceSlug = "crm-pipeline", serviceName = "CRM Pipeline Commercial") {
5840
5727
  const cleanTopic = trend.topicName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
@@ -5894,7 +5781,7 @@ class SocialTrendSeoGenerator {
5894
5781
  ];
5895
5782
  }
5896
5783
  }
5897
- // src/crosslink-scorer.ts
5784
+ // packages/lynx-seo-engine/src/crosslink-scorer.ts
5898
5785
  class CrosslinkScorerEngine {
5899
5786
  static computeCrosslinkScore(source, candidate) {
5900
5787
  if (source.slug === candidate.slug)
@@ -5945,7 +5832,7 @@ class CrosslinkScorerEngine {
5945
5832
  return suggestions.sort((a, b) => b.score - a.score).slice(0, maxLinks);
5946
5833
  }
5947
5834
  }
5948
- // src/instant-matrix-search.ts
5835
+ // packages/lynx-seo-engine/src/instant-matrix-search.ts
5949
5836
  class InstantMatrixSearchEngine {
5950
5837
  static search(query, pages, limit = 10) {
5951
5838
  const cleanQuery = query.trim().toLowerCase();
@@ -5967,7 +5854,7 @@ class InstantMatrixSearchEngine {
5967
5854
  }).filter((item) => item.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((item) => item.page);
5968
5855
  }
5969
5856
  }
5970
- // src/rss-syndication-feed.ts
5857
+ // packages/lynx-seo-engine/src/rss-syndication-feed.ts
5971
5858
  class RssSyndicationFeedGenerator {
5972
5859
  static generateRss2(opts) {
5973
5860
  const itemsXml = opts.items.map((item) => `
@@ -5996,7 +5883,7 @@ ${itemsXml}
5996
5883
  </rss>`.trim();
5997
5884
  }
5998
5885
  }
5999
- // src/embeddable-seo-widget.ts
5886
+ // packages/lynx-seo-engine/src/embeddable-seo-widget.ts
6000
5887
  class EmbeddableSeoWidgetGenerator {
6001
5888
  static generateWidgetJs(apiBaseUrl) {
6002
5889
  return `
@@ -6044,7 +5931,7 @@ class EmbeddableSeoWidgetGenerator {
6044
5931
  `.trim();
6045
5932
  }
6046
5933
  }
6047
- // src/ngram-density-analyzer.ts
5934
+ // packages/lynx-seo-engine/src/ngram-density-analyzer.ts
6048
5935
  class NGramDensityAnalyzer {
6049
5936
  static stopwords = new Set([
6050
5937
  "le",
@@ -6153,7 +6040,7 @@ class NGramDensityAnalyzer {
6153
6040
  })).sort((a, b) => b.count - a.count);
6154
6041
  }
6155
6042
  }
6156
- // src/isr-cache-manager.ts
6043
+ // packages/lynx-seo-engine/src/isr-cache-manager.ts
6157
6044
  class IsrCacheManager {
6158
6045
  static cache = new Map;
6159
6046
  static defaultTtlMs = 24 * 3600 * 1000;
@@ -6191,7 +6078,7 @@ class IsrCacheManager {
6191
6078
  return this.cache.size;
6192
6079
  }
6193
6080
  }
6194
- // src/copy-frameworks-master.ts
6081
+ // packages/lynx-seo-engine/src/copy-frameworks-master.ts
6195
6082
  class CopywritingFrameworksMaster {
6196
6083
  static generateHeadlines(opts) {
6197
6084
  return {
@@ -6225,7 +6112,7 @@ class CopywritingFrameworksMaster {
6225
6112
  ];
6226
6113
  }
6227
6114
  }
6228
- // src/social-ads-seo.ts
6115
+ // packages/lynx-seo-engine/src/social-ads-seo.ts
6229
6116
  class SocialAdsSocialSeoEngine {
6230
6117
  static auditLinkedInTrendsForSeo(industry = "avocats", serviceSlug = "crm-pipeline", serviceName = "CRM Pipeline") {
6231
6118
  return [
@@ -6361,7 +6248,7 @@ ${template.targetHashtags.join(" ")}
6361
6248
  ];
6362
6249
  }
6363
6250
  }
6364
- // src/ad-intelligence-cro.ts
6251
+ // packages/lynx-seo-engine/src/ad-intelligence-cro.ts
6365
6252
  class AdIntelligenceCroEngine {
6366
6253
  static inspectCompetitorAds(competitorDomain, serviceName = "CRM Pipeline") {
6367
6254
  const brand = competitorDomain.replace(/^https?:\/\//, "").split(".")[0];
@@ -6445,7 +6332,7 @@ Avec ${opts.serviceName}, tout est automatisé en tâche de fond pour vous appor
6445
6332
  ];
6446
6333
  }
6447
6334
  }
6448
- // src/rank-math-parity.ts
6335
+ // packages/lynx-seo-engine/src/rank-math-parity.ts
6449
6336
  class RankMathParityEngine {
6450
6337
  static calculateOnPageScore(opts) {
6451
6338
  const kw = opts.focusKeyword.trim().toLowerCase();
@@ -6599,7 +6486,7 @@ class RankMathParityEngine {
6599
6486
  `);
6600
6487
  }
6601
6488
  }
6602
- // src/yoast-parity.ts
6489
+ // packages/lynx-seo-engine/src/yoast-parity.ts
6603
6490
  class YoastParityEngine {
6604
6491
  static frenchTransitionWords = [
6605
6492
  "en effet",
@@ -6714,7 +6601,7 @@ class YoastParityEngine {
6714
6601
  };
6715
6602
  }
6716
6603
  }
6717
- // src/social-growth-suite.ts
6604
+ // packages/lynx-seo-engine/src/social-growth-suite.ts
6718
6605
  class SocialGrowthSuite {
6719
6606
  static generateCarouselDeck(opts) {
6720
6607
  return {
@@ -6920,7 +6807,7 @@ Voici le guide complet en 6 slides pour automatiser votre acquisition en 2026 \u
6920
6807
  ];
6921
6808
  }
6922
6809
  }
6923
- // src/team-rbac.ts
6810
+ // packages/lynx-seo-engine/src/team-rbac.ts
6924
6811
  var ROLE_PERMISSIONS = {
6925
6812
  owner: [
6926
6813
  "project:delete",
@@ -6957,7 +6844,7 @@ class TeamRbacEngine {
6957
6844
  return permissions.includes(action);
6958
6845
  }
6959
6846
  }
6960
- // src/real-reviews-sync.ts
6847
+ // packages/lynx-seo-engine/src/real-reviews-sync.ts
6961
6848
  class RealReviewsSyncEngine {
6962
6849
  static async fetchGooglePlacesReviews(opts) {
6963
6850
  try {
@@ -7080,7 +6967,7 @@ class RealReviewsSyncEngine {
7080
6967
  `;
7081
6968
  }
7082
6969
  }
7083
- // src/google-business-profile.ts
6970
+ // packages/lynx-seo-engine/src/google-business-profile.ts
7084
6971
  class GoogleBusinessProfileEngine {
7085
6972
  static generateLocalBusinessSchema(config) {
7086
6973
  const schema = {
@@ -7294,7 +7181,7 @@ class GoogleBusinessProfileEngine {
7294
7181
  };
7295
7182
  }
7296
7183
  }
7297
- // src/video-youtube-analyzer.ts
7184
+ // packages/lynx-seo-engine/src/video-youtube-analyzer.ts
7298
7185
  class VideoYouTubeAnalyzer {
7299
7186
  static extractVideoId(urlOrIframe) {
7300
7187
  const regExp = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
@@ -7348,7 +7235,7 @@ class VideoYouTubeAnalyzer {
7348
7235
  `.trim();
7349
7236
  }
7350
7237
  }
7351
- // src/power-words-psychology.ts
7238
+ // packages/lynx-seo-engine/src/power-words-psychology.ts
7352
7239
  var MULTILINGUAL_POWER_WORDS = {
7353
7240
  fr: {
7354
7241
  authority: [
@@ -7368,7 +7255,8 @@ var MULTILINGUAL_POWER_WORDS = {
7368
7255
  "authentique",
7369
7256
  "infaillible",
7370
7257
  "reconnu",
7371
- "démontré"
7258
+ "démontré",
7259
+ "avis"
7372
7260
  ],
7373
7261
  urgency: [
7374
7262
  "rapide",
@@ -7383,7 +7271,8 @@ var MULTILINGUAL_POWER_WORDS = {
7383
7271
  "en 5 min",
7384
7272
  "en 10 min",
7385
7273
  "aujourd'hui",
7386
- "débloquer"
7274
+ "débloquer",
7275
+ "vite"
7387
7276
  ],
7388
7277
  value: [
7389
7278
  "gratuit",
@@ -7399,7 +7288,9 @@ var MULTILINGUAL_POWER_WORDS = {
7399
7288
  "économisez",
7400
7289
  "inclus",
7401
7290
  "accessible",
7402
- "inédit"
7291
+ "inédit",
7292
+ "remise",
7293
+ "promo"
7403
7294
  ],
7404
7295
  curiosity: [
7405
7296
  "exclusif",
@@ -7415,7 +7306,8 @@ var MULTILINGUAL_POWER_WORDS = {
7415
7306
  "choc",
7416
7307
  "incontournable",
7417
7308
  "mystère",
7418
- "incroyable"
7309
+ "incroyable",
7310
+ "vérité"
7419
7311
  ],
7420
7312
  sentimentPositive: [
7421
7313
  "parfait",
@@ -7444,7 +7336,8 @@ var MULTILINGUAL_POWER_WORDS = {
7444
7336
  "catastrophe",
7445
7337
  "risqué",
7446
7338
  "menace",
7447
- "perte"
7339
+ "perte",
7340
+ "alerte"
7448
7341
  ]
7449
7342
  },
7450
7343
  en: {
@@ -7463,7 +7356,9 @@ var MULTILINGUAL_POWER_WORDS = {
7463
7356
  "authority",
7464
7357
  "case study",
7465
7358
  "benchmark",
7466
- "professional"
7359
+ "professional",
7360
+ "review",
7361
+ "formula"
7467
7362
  ],
7468
7363
  urgency: [
7469
7364
  "instant",
@@ -7475,228 +7370,479 @@ var MULTILINGUAL_POWER_WORDS = {
7475
7370
  "deadline",
7476
7371
  "last chance",
7477
7372
  "step-by-step",
7478
- "overnight",
7479
- "rapid",
7480
- "minutes"
7373
+ "in 5 minutes",
7374
+ "immediate",
7375
+ "urgent",
7376
+ "unlock",
7377
+ "rapid"
7481
7378
  ],
7482
7379
  value: [
7483
7380
  "free",
7484
7381
  "affordable",
7485
- "guaranteed",
7486
7382
  "save",
7487
- "profit",
7488
- "profitable",
7383
+ "guaranteed",
7384
+ "easy",
7489
7385
  "bonus",
7490
- "cheap",
7491
- "priceless",
7386
+ "discount",
7492
7387
  "effortless",
7493
7388
  "lifetime",
7494
- "budget"
7389
+ "roi",
7390
+ "value",
7391
+ "exclusive deal",
7392
+ "profitable"
7495
7393
  ],
7496
7394
  curiosity: [
7497
7395
  "secret",
7498
- "secrets",
7499
- "exclusive",
7500
7396
  "revealed",
7397
+ "insider",
7501
7398
  "hacks",
7502
- "tricks",
7503
- "hacks",
7504
- "behind the scenes",
7505
- "uncovered",
7399
+ "why",
7400
+ "how to",
7401
+ "untold",
7506
7402
  "surprising",
7507
- "insider",
7508
- "confidential",
7509
- "jaw-dropping"
7403
+ "shocking",
7404
+ "hidden",
7405
+ "must-know",
7406
+ "unbelievable",
7407
+ "myth"
7510
7408
  ],
7511
7409
  sentimentPositive: [
7512
7410
  "amazing",
7513
- "awesome",
7514
7411
  "brilliant",
7412
+ "powerful",
7515
7413
  "epic",
7516
- "legendary",
7517
- "superb",
7518
- "stunning",
7519
7414
  "perfect",
7520
- "powerful",
7521
- "triumph",
7522
- "miracle",
7523
- "flawless"
7415
+ "stunning",
7416
+ "thriving",
7417
+ "seamless",
7418
+ "exceptional",
7419
+ "masterpiece",
7420
+ "unbeatable"
7524
7421
  ],
7525
7422
  sentimentNegative: [
7526
7423
  "mistake",
7527
7424
  "warning",
7528
- "deadly",
7425
+ "fail",
7426
+ "avoid",
7427
+ "risk",
7428
+ "trap",
7529
7429
  "worst",
7530
- "danger",
7531
- "toxic",
7532
- "destroy",
7533
- "ruin",
7534
7430
  "scam",
7535
- "nightmare"
7431
+ "danger",
7432
+ "flaw"
7536
7433
  ]
7537
7434
  },
7538
7435
  es: {
7539
- authority: ["guía", "completo", "definitivo", "experto", "oficial", "mejor", "mejores", "certificado", "profesional", "maestro"],
7540
- urgency: ["rápido", "ahora", "inmediato", "2026", "hoy", "urgente", "en minutos", "paso a paso"],
7541
- value: ["gratis", "gratuito", "económico", "garantizado", "ahorra", "rentable", "oferta", "sin riesgo"],
7542
- curiosity: ["secreto", "exclusivo", "revelado", "trucos", "increíble", "top", "método", "descubre"],
7543
- sentimentPositive: ["increíble", "fantástico", "perfecto", "excelente", "maravilloso", "potente", "éxito"],
7544
- sentimentNegative: ["error", "peligro", "evitar", "peor", "estafa", "trampa", "arruinar"]
7436
+ authority: [
7437
+ "definitiva",
7438
+ "completa",
7439
+ "guía",
7440
+ "experto",
7441
+ "oficial",
7442
+ "certificado",
7443
+ "mejor",
7444
+ "mejores",
7445
+ "comparativa",
7446
+ "profesional",
7447
+ "comprobado",
7448
+ "líder",
7449
+ "análisis"
7450
+ ],
7451
+ urgency: [
7452
+ "rápido",
7453
+ "ahora",
7454
+ "urgente",
7455
+ "hoy",
7456
+ "2026",
7457
+ "en 5 minutos",
7458
+ "inmediato",
7459
+ "última oportunidad",
7460
+ "fácil"
7461
+ ],
7462
+ value: [
7463
+ "gratis",
7464
+ "económico",
7465
+ "ahorra",
7466
+ "garantizado",
7467
+ "rentable",
7468
+ "oferta",
7469
+ "descuento",
7470
+ "exclusivo"
7471
+ ],
7472
+ curiosity: [
7473
+ "secreto",
7474
+ "revelado",
7475
+ "trucos",
7476
+ "por qué",
7477
+ "cómo",
7478
+ "impactante",
7479
+ "increíble",
7480
+ "descubre",
7481
+ "método"
7482
+ ],
7483
+ sentimentPositive: [
7484
+ "excelente",
7485
+ "increíble",
7486
+ "perfecto",
7487
+ "potente",
7488
+ "maravilloso",
7489
+ "éxito",
7490
+ "fantástico"
7491
+ ],
7492
+ sentimentNegative: [
7493
+ "error",
7494
+ "peligro",
7495
+ "evita",
7496
+ "peor",
7497
+ "estafa",
7498
+ "trampa",
7499
+ "fracaso",
7500
+ "riesgo"
7501
+ ]
7545
7502
  },
7546
7503
  de: {
7547
- authority: ["leitfaden", "komplett", "experte", "offiziell", "beste", "bester", "zertifiziert", "vergleich", "meister"],
7548
- urgency: ["schnell", "jetzt", "sofort", "2026", "heute", "schritt-für-schritt", "in 5 minuten"],
7549
- value: ["kostenlos", "gratis", "sparen", "garantiert", "günstig", "rendite", "ohne risiko"],
7550
- curiosity: ["geheim", "exklusiv", "tipps", "tricks", "enthüllt", "top", "warum", "entdecken"],
7551
- sentimentPositive: ["perfekt", "genial", "hervorragend", "leistungsstark", "erfolg", "wunderbar"],
7552
- sentimentNegative: ["fehler", "gefahr", "vermeiden", "schlimmste", "falle", "risiko"]
7504
+ authority: [
7505
+ "ultimativ",
7506
+ "vollständig",
7507
+ "leitfaden",
7508
+ "experte",
7509
+ "offiziell",
7510
+ "zertifiziert",
7511
+ "beste",
7512
+ "bester",
7513
+ "vergleich",
7514
+ "profi"
7515
+ ],
7516
+ urgency: [
7517
+ "schnell",
7518
+ "jetzt",
7519
+ "sofort",
7520
+ "2026",
7521
+ "in 5 minuten",
7522
+ "heute",
7523
+ "dringend",
7524
+ "einfach"
7525
+ ],
7526
+ value: [
7527
+ "kostenlos",
7528
+ "gratis",
7529
+ "sparen",
7530
+ "garantiert",
7531
+ "rabatt",
7532
+ "günstig",
7533
+ "angebot",
7534
+ "profitabel"
7535
+ ],
7536
+ curiosity: [
7537
+ "geheimnis",
7538
+ "enthüllt",
7539
+ "tricks",
7540
+ "tipps",
7541
+ "warum",
7542
+ "wie man",
7543
+ "unglaublich",
7544
+ "entdecken"
7545
+ ],
7546
+ sentimentPositive: [
7547
+ "hervorragend",
7548
+ "perfekt",
7549
+ "genial",
7550
+ "erfolg",
7551
+ "fantastisch",
7552
+ "wunderbar",
7553
+ "stark"
7554
+ ],
7555
+ sentimentNegative: [
7556
+ "fehler",
7557
+ "gefahr",
7558
+ "vermeiden",
7559
+ "schlimmste",
7560
+ "betrug",
7561
+ "risiko",
7562
+ "warnung"
7563
+ ]
7553
7564
  },
7554
7565
  it: {
7555
- authority: ["guida", "completa", "esperto", "ufficiale", "migliore", "migliori", "certificato", "professionale"],
7556
- urgency: ["veloce", "ora", "subito", "2026", "oggi", "passo dopo passo", "in pochi minuti"],
7557
- value: ["gratis", "gratuito", "economico", "garantito", "risparmio", "conveniente", "senza rischi"],
7558
- curiosity: ["segreto", "esclusivo", "trucchi", "rivelato", "top", "metodo", "scopri"],
7559
- sentimentPositive: ["perfetto", "fantastico", "eccellente", "potente", "successo", "incredibile"],
7560
- sentimentNegative: ["errore", "pericolo", "evitare", "peggiore", "truffa", "trappola"]
7566
+ authority: [
7567
+ "guida",
7568
+ "completa",
7569
+ "esperto",
7570
+ "ufficiale",
7571
+ "certificato",
7572
+ "migliore",
7573
+ "migliori",
7574
+ "confronto",
7575
+ "definitiva",
7576
+ "professionale"
7577
+ ],
7578
+ urgency: [
7579
+ "veloce",
7580
+ "ora",
7581
+ "subito",
7582
+ "immediato",
7583
+ "2026",
7584
+ "in 5 minuti",
7585
+ "oggi",
7586
+ "urgente"
7587
+ ],
7588
+ value: [
7589
+ "gratis",
7590
+ "gratuito",
7591
+ "risparmia",
7592
+ "garantito",
7593
+ "sconto",
7594
+ "facile",
7595
+ "offerta",
7596
+ "conveniente"
7597
+ ],
7598
+ curiosity: [
7599
+ "segreto",
7600
+ "svelato",
7601
+ "trucchi",
7602
+ "perché",
7603
+ "come fare",
7604
+ "incredibile",
7605
+ "scopri",
7606
+ "metodo"
7607
+ ],
7608
+ sentimentPositive: [
7609
+ "perfetto",
7610
+ "incredibile",
7611
+ "fantastico",
7612
+ "successo",
7613
+ "eccezionale",
7614
+ "meraviglioso"
7615
+ ],
7616
+ sentimentNegative: [
7617
+ "errore",
7618
+ "pericolo",
7619
+ "evitare",
7620
+ "peggiore",
7621
+ "truffa",
7622
+ "rischio",
7623
+ "trappola"
7624
+ ]
7561
7625
  },
7562
7626
  nl: {
7563
- authority: ["gids", "compleet", "expert", "officieel", "beste", "gecertificeerd", "professioneel"],
7564
- urgency: ["snel", "nu", "direct", "2026", "vandaag", "stap voor stap"],
7565
- value: ["gratis", "goedkoop", "gegarandeerd", "bespaar", "rendement", "zonder risico"],
7566
- curiosity: ["geheim", "exclusief", "tips", "onthuld", "top", "ontdek"],
7567
- sentimentPositive: ["perfect", "geweldig", "uitstekend", "krachtig", "succes"],
7568
- sentimentNegative: ["fout", "gevaar", "vermijden", "slechtste", "valkuil"]
7627
+ authority: ["ultiem", "gids", "expert", "officieel", "beste", "vergelijk", "compleet", "bewezen"],
7628
+ urgency: ["snel", "nu", "direct", "vandaag", "2026", "meteen", "eenvoudig"],
7629
+ value: ["gratis", "bespaar", "gegarandeerd", "korting", "goedkoop", "voordeel"],
7630
+ curiosity: ["geheim", "onthuld", "tips", "waarom", "hoe", "ontdek"],
7631
+ sentimentPositive: ["geweldig", "perfect", "uitstekend", "succes", "fantastisch"],
7632
+ sentimentNegative: ["fout", "gevaar", "vermijd", "slechtste", "oplichting", "risico"]
7569
7633
  },
7570
7634
  pt: {
7571
- authority: ["guia", "completo", "definitivo", "especialista", "oficial", "melhor", "melhores", "certificado"],
7572
- urgency: ["rápido", "agora", "imediato", "2026", "hoje", "passo a passo"],
7573
- value: ["grátis", "gratuito", "econômico", "garantido", "economize", "sem risco"],
7574
- curiosity: ["segredo", "exclusivo", "revelado", "truques", "top", "descubra"],
7575
- sentimentPositive: ["incrível", "perfeito", "excelente", "poderoso", "sucesso"],
7576
- sentimentNegative: ["erro", "perigo", "evitar", "pior", "golpe"]
7635
+ authority: ["guia", "completo", "definitivo", "especialista", "oficial", "melhor", "melhores", "comparativo"],
7636
+ urgency: ["rápido", "agora", "imediato", "hoje", "2026", "em 5 minutos", "urgente"],
7637
+ value: ["grátis", "gratuito", "economize", "garantido", "desconto", "fácil", "oferta"],
7638
+ curiosity: ["segredo", "revelado", "dicas", "por que", "como fazer", "incrível", "descubra"],
7639
+ sentimentPositive: ["perfeito", "incrível", "fantástico", "sucesso", "excelente"],
7640
+ sentimentNegative: ["erro", "perigo", "evite", "pior", "golpe", "risco", "cilada"]
7641
+ },
7642
+ ar: {
7643
+ authority: ["دليل", "شامل", "رسمي", "خبير", "أفضل", "مقارنة", "معتمد", "نهائي"],
7644
+ urgency: ["سريع", "الآن", "فوري", "اليوم", "2026", "في دقائق", "عاجل"],
7645
+ value: ["مجانا", "وفر", "مضمون", "خصم", "سهل", "عرض", "مميز"],
7646
+ curiosity: ["سر", "كشف", "أسرار", "لماذا", "كيف", "مذهل", "اكتشف"],
7647
+ sentimentPositive: ["رائع", "ممتاز", "ناجح", "مبهر", "مثالي"],
7648
+ sentimentNegative: ["خطأ", "تحذير", "تجنب", "فخ", "احتيال", "خطر"]
7649
+ },
7650
+ ru: {
7651
+ authority: ["руководство", "полный", "эксперт", "официальный", "лучший", "лучшие", "сравнение", "проверенный"],
7652
+ urgency: ["быстро", "сейчас", "срочно", "сегодня", "2026", "за 5 минут", "немедленно"],
7653
+ value: ["бесплатно", "скидка", "гарантия", "выгодно", "легко", "акция"],
7654
+ curiosity: ["секрет", "раскрыт", "лайфхаки", "почему", "как", "невероятный", "узнайте"],
7655
+ sentimentPositive: ["отлично", "идеально", "успех", "потрясающий", "великолепный"],
7656
+ sentimentNegative: ["ошибка", "опасность", "избегать", "худший", "обман", "риск"]
7657
+ },
7658
+ zh: {
7659
+ authority: ["终极", "完整", "指南", "专家", "官方", "最佳", "对比", "评测", "权威"],
7660
+ urgency: ["快速", "立即", "今天", "2026", "5分钟", "马上", "紧急"],
7661
+ value: ["免费", "省钱", "保证", "优惠", "简单", "折扣", "高性价比"],
7662
+ curiosity: ["秘密", "揭秘", "技巧", "为什么", "如何", "必看", "探索"],
7663
+ sentimentPositive: ["完美", "惊人", "卓越", "成功", "极佳", "出色"],
7664
+ sentimentNegative: ["错误", "陷阱", "避免", "危险", "骗局", "风险"]
7665
+ },
7666
+ ja: {
7667
+ authority: ["完全ガイド", "究極", "公式", "専門家", "おすすめ", "徹底比較", "決定版", "プロ"],
7668
+ urgency: ["今すぐ", "速報", "最短", "2026年", "今日", "5分で", "簡単"],
7669
+ value: ["無料", "お得", "割引", "保証", "コスパ", "特典", "プレゼント"],
7670
+ curiosity: ["秘密", "裏ワザ", "暴露", "なぜ", "方法", "必見", "真実"],
7671
+ sentimentPositive: ["最高", "完璧", "圧倒的", "成功", "絶賛", "素晴らしい"],
7672
+ sentimentNegative: ["失敗", "注意", "危険", "避けるべき", "詐欺", "罠"]
7673
+ },
7674
+ hi: {
7675
+ authority: ["गाइड", "सम्पूर्ण", "विशेषज्ञ", "आधिकारिक", "सर्वश्रेष्ठ", "तुलना", "सटीक"],
7676
+ urgency: ["तुरंत", "अभी", "आज", "2026", "5 मिनट में", "जल्दी"],
7677
+ value: ["मुफ्त", "बचत", "गारंटी", "छूट", "आसान", "ऑफर"],
7678
+ curiosity: ["रहस्य", "खुलासा", "टिप्स", "क्यों", "कैसे", "अनोखा"],
7679
+ sentimentPositive: ["उत्कृष्ट", "शानदार", "सफल", "अद्भुत", "बेहतरीन"],
7680
+ sentimentNegative: ["गलती", "खतरा", "सावधान", "धोखा", "नुकसान"]
7577
7681
  }
7578
7682
  };
7579
7683
 
7580
7684
  class PowerWordsPsychologyEngine {
7581
- static analyzeTitlePsychology(title, lang = "fr") {
7582
- const cleanTitle = title.toLowerCase();
7583
- const dict = MULTILINGUAL_POWER_WORDS[lang] || MULTILINGUAL_POWER_WORDS.fr;
7584
- const detectedPowerWords = [];
7585
- let score = 30;
7586
- const hasAuthority = dict.authority.some((w) => {
7587
- if (cleanTitle.includes(w)) {
7588
- detectedPowerWords.push(w);
7589
- return true;
7685
+ static registerLanguageWords(langCode, words) {
7686
+ const code = langCode.toLowerCase().trim();
7687
+ if (!MULTILINGUAL_POWER_WORDS[code]) {
7688
+ MULTILINGUAL_POWER_WORDS[code] = {
7689
+ authority: [],
7690
+ urgency: [],
7691
+ value: [],
7692
+ curiosity: [],
7693
+ sentimentPositive: [],
7694
+ sentimentNegative: []
7695
+ };
7696
+ }
7697
+ if (words.authority)
7698
+ MULTILINGUAL_POWER_WORDS[code].authority.push(...words.authority);
7699
+ if (words.urgency)
7700
+ MULTILINGUAL_POWER_WORDS[code].urgency.push(...words.urgency);
7701
+ if (words.value)
7702
+ MULTILINGUAL_POWER_WORDS[code].value.push(...words.value);
7703
+ if (words.curiosity)
7704
+ MULTILINGUAL_POWER_WORDS[code].curiosity.push(...words.curiosity);
7705
+ if (words.sentimentPositive)
7706
+ MULTILINGUAL_POWER_WORDS[code].sentimentPositive.push(...words.sentimentPositive);
7707
+ if (words.sentimentNegative)
7708
+ MULTILINGUAL_POWER_WORDS[code].sentimentNegative.push(...words.sentimentNegative);
7709
+ }
7710
+ static getSupportedLanguages() {
7711
+ return Object.keys(MULTILINGUAL_POWER_WORDS);
7712
+ }
7713
+ static analyzeTitle(title, lang = "fr") {
7714
+ const raw = (title || "").toLowerCase().trim();
7715
+ const langKey = lang.toLowerCase().trim();
7716
+ const primaryBank = MULTILINGUAL_POWER_WORDS[langKey] || MULTILINGUAL_POWER_WORDS["en"] || MULTILINGUAL_POWER_WORDS["fr"];
7717
+ const allBanks = [primaryBank];
7718
+ if (langKey !== "en" && MULTILINGUAL_POWER_WORDS["en"])
7719
+ allBanks.push(MULTILINGUAL_POWER_WORDS["en"]);
7720
+ const detectedWords = [];
7721
+ let authorityMatch = false;
7722
+ let urgencyMatch = false;
7723
+ let valueMatch = false;
7724
+ let curiosityMatch = false;
7725
+ let positiveCount = 0;
7726
+ let negativeCount = 0;
7727
+ for (const bank of allBanks) {
7728
+ for (const word of bank.authority) {
7729
+ if (raw.includes(word.toLowerCase())) {
7730
+ authorityMatch = true;
7731
+ if (!detectedWords.includes(word))
7732
+ detectedWords.push(word);
7733
+ }
7590
7734
  }
7591
- return false;
7592
- });
7593
- if (hasAuthority)
7594
- score += 20;
7595
- const hasUrgency = dict.urgency.some((w) => {
7596
- if (cleanTitle.includes(w)) {
7597
- detectedPowerWords.push(w);
7598
- return true;
7735
+ for (const word of bank.urgency) {
7736
+ if (raw.includes(word.toLowerCase())) {
7737
+ urgencyMatch = true;
7738
+ if (!detectedWords.includes(word))
7739
+ detectedWords.push(word);
7740
+ }
7599
7741
  }
7600
- return false;
7601
- });
7602
- if (hasUrgency)
7603
- score += 15;
7604
- const hasValue = dict.value.some((w) => {
7605
- if (cleanTitle.includes(w)) {
7606
- detectedPowerWords.push(w);
7607
- return true;
7742
+ for (const word of bank.value) {
7743
+ if (raw.includes(word.toLowerCase())) {
7744
+ valueMatch = true;
7745
+ if (!detectedWords.includes(word))
7746
+ detectedWords.push(word);
7747
+ }
7608
7748
  }
7609
- return false;
7610
- });
7611
- if (hasValue)
7612
- score += 15;
7613
- const hasCuriosity = dict.curiosity.some((w) => {
7614
- if (cleanTitle.includes(w)) {
7615
- detectedPowerWords.push(w);
7616
- return true;
7749
+ for (const word of bank.curiosity) {
7750
+ if (raw.includes(word.toLowerCase())) {
7751
+ curiosityMatch = true;
7752
+ if (!detectedWords.includes(word))
7753
+ detectedWords.push(word);
7754
+ }
7617
7755
  }
7618
- return false;
7619
- });
7620
- if (hasCuriosity)
7756
+ for (const word of bank.sentimentPositive) {
7757
+ if (raw.includes(word.toLowerCase())) {
7758
+ positiveCount++;
7759
+ if (!detectedWords.includes(word))
7760
+ detectedWords.push(word);
7761
+ }
7762
+ }
7763
+ for (const word of bank.sentimentNegative) {
7764
+ if (raw.includes(word.toLowerCase())) {
7765
+ negativeCount++;
7766
+ if (!detectedWords.includes(word))
7767
+ detectedWords.push(word);
7768
+ }
7769
+ }
7770
+ }
7771
+ const hasNumber = /\b\d+\b/.test(raw);
7772
+ const hasYear = /\b(202[4-9]|203[0-9])\b/.test(raw);
7773
+ const hasCurrencyOrDiscount = /[\$€£¥₹%]|د\.إ|﷼|\b(promo|soldes|discount|deal|off)\b/i.test(raw);
7774
+ const hasBracketsOrParentheses = /[\[\]\(\)\{\}【】《》「」]/.test(raw);
7775
+ let score = 30;
7776
+ if (detectedWords.length >= 1)
7777
+ score += 20;
7778
+ if (detectedWords.length >= 2)
7779
+ score += 10;
7780
+ if (detectedWords.length >= 3)
7621
7781
  score += 10;
7622
- const hasNumber = /\d+/.test(title);
7623
7782
  if (hasNumber)
7783
+ score += 15;
7784
+ if (hasYear)
7624
7785
  score += 10;
7625
- const currentYear = new Date().getFullYear().toString();
7626
- const hasYear = title.includes(currentYear) || title.includes("2026");
7786
+ if (hasCurrencyOrDiscount)
7787
+ score += 5;
7788
+ if (hasBracketsOrParentheses)
7789
+ score += 5;
7790
+ if (score > 100)
7791
+ score = 100;
7627
7792
  let sentiment = "neutre";
7628
- const hasPositive = dict.sentimentPositive.some((w) => cleanTitle.includes(w));
7629
- const hasNegative = dict.sentimentNegative.some((w) => cleanTitle.includes(w));
7630
- if (hasPositive) {
7793
+ if (positiveCount > negativeCount)
7631
7794
  sentiment = "positif";
7632
- } else if (hasNegative) {
7795
+ else if (negativeCount > positiveCount)
7633
7796
  sentiment = "negatif";
7634
- }
7635
7797
  const recommendations = [];
7636
- if (!detectedPowerWords.length) {
7637
- recommendations.push("Ajoutez au moins un mot d'impact (*Power Word*) comme 'Guide Complet', 'Meilleur' ou 'Ultime'.");
7798
+ if (detectedWords.length === 0) {
7799
+ recommendations.push("Ajoutez au moins 1 mot d'impact émotionnel ou d'autorité (ex: 'Guide', 'Ultime', 'Meilleur').");
7638
7800
  }
7639
7801
  if (!hasNumber) {
7640
- recommendations.push("Intégrez un chiffre ou l'année en cours (ex: '7 astuces', '2026') pour booster le taux de clic de +36%.");
7802
+ recommendations.push("Intégrez un chiffre (ex: 'Les 7 Meilleurs...') pour augmenter le taux de clic de +36%.");
7641
7803
  }
7642
- if (title.length < 35) {
7643
- recommendations.push("Titre trop court : enrichissez votre promesse de valeur pour occuper les 600px de la SERP Google.");
7804
+ if (!hasYear) {
7805
+ recommendations.push("Indiquez l'année courante (2026) pour signaler la fraîcheur du contenu aux internautes.");
7644
7806
  }
7645
- const suggestedTitles = [];
7646
- if (lang === "fr") {
7647
- suggestedTitles.push(`${title} : Guide Ultime 2026`);
7648
- suggestedTitles.push(`Les 5 Meilleurs ${title} (Comparatif & Avis)`);
7649
- suggestedTitles.push(`${title} — Solution Rapide & Complète`);
7650
- } else {
7651
- suggestedTitles.push(`${title}: The Ultimate 2026 Guide`);
7652
- suggestedTitles.push(`Top 5 Best ${title} (Full Review & Comparison)`);
7653
- suggestedTitles.push(`${title} — Proven & Fast Method`);
7807
+ if (!hasBracketsOrParentheses) {
7808
+ recommendations.push("Utilisez des crochets ou parenthèses [Guide 2026] pour structurer visuellement l'extrait.");
7654
7809
  }
7810
+ const cleanSubject = title.replace(/\(.*?\)|\[.*?\]/g, "").trim();
7811
+ const suggestedTitles = [
7812
+ `Les 7 Meilleurs ${cleanSubject} [Guide Ultime 2026]`,
7813
+ `Comment Maîtriser ${cleanSubject} en 5 Étapes (Méthode 2026)`,
7814
+ `${cleanSubject} : Avis, Comparatif et Pièges à Éviter (2026)`
7815
+ ];
7655
7816
  return {
7656
- score: Math.min(100, score),
7657
- powerWordsDetected: Array.from(new Set(detectedPowerWords)),
7817
+ score,
7818
+ powerWordsDetected: detectedWords,
7658
7819
  sentiment,
7659
7820
  hasNumber,
7660
7821
  hasYear,
7661
- hasCuriosityTrigger: hasCuriosity,
7662
- hasUrgencyTrigger: hasUrgency,
7663
- hasAuthorityTrigger: hasAuthority,
7822
+ hasCuriosityTrigger: curiosityMatch,
7823
+ hasUrgencyTrigger: urgencyMatch,
7824
+ hasAuthorityTrigger: authorityMatch,
7825
+ hasCurrencyOrDiscount,
7826
+ hasBracketsOrParentheses,
7664
7827
  recommendations,
7665
7828
  suggestedTitles
7666
7829
  };
7667
7830
  }
7668
- static enrichProgrammaticTitle(service, locationOrCompetitor, type = "geo", lang = "fr") {
7669
- const year = "2026";
7670
- if (lang === "fr") {
7671
- if (type === "geo") {
7672
- return `Meilleur ${service} à ${locationOrCompetitor} : Guide Complet ${year}`;
7673
- } else if (type === "vs") {
7674
- return `${service} vs ${locationOrCompetitor} : Le Comparatif Ultime & Avis`;
7675
- } else {
7676
- return `Top 5 Alternatives à ${locationOrCompetitor} : Comparatif ${year}`;
7677
- }
7678
- } else if (lang === "en") {
7679
- if (type === "geo") {
7680
- return `Best ${service} in ${locationOrCompetitor}: Ultimate ${year} Guide`;
7681
- } else if (type === "vs") {
7682
- return `${service} vs ${locationOrCompetitor}: Definitive Comparison`;
7683
- } else {
7684
- return `Top 5 Alternatives to ${locationOrCompetitor} (${year} Review)`;
7685
- }
7686
- } else if (lang === "es") {
7687
- if (type === "geo") {
7688
- return `Mejor ${service} en ${locationOrCompetitor}: Guía Completa ${year}`;
7689
- } else {
7690
- return `${service} vs ${locationOrCompetitor}: Comparativa Definitiva`;
7691
- }
7692
- } else if (lang === "de") {
7693
- return `Beste ${service} in ${locationOrCompetitor}: Kompletter Leitfaden ${year}`;
7694
- } else {
7695
- return `${service} in ${locationOrCompetitor} (${year})`;
7831
+ static enrichProgrammaticTitle(baseTitle, lang = "fr") {
7832
+ const analysis = this.analyzeTitle(baseTitle, lang);
7833
+ if (analysis.score >= 80)
7834
+ return baseTitle;
7835
+ let enriched = baseTitle.trim();
7836
+ if (!analysis.hasNumber && !enriched.startsWith("Top ") && !enriched.startsWith("Les ")) {
7837
+ enriched = `Les Meilleurs ${enriched}`;
7838
+ }
7839
+ if (!analysis.hasYear) {
7840
+ enriched = `${enriched} (Guide 2026)`;
7696
7841
  }
7842
+ return enriched;
7697
7843
  }
7698
7844
  }
7699
- // src/index.ts
7845
+ // packages/lynx-seo-engine/src/index.ts
7700
7846
  function createLynxSeoEngine(config) {
7701
7847
  return new LynxSeoEngine(config);
7702
7848
  }
@@ -7741,3 +7887,77 @@ var LynxSeo = {
7741
7887
  realReviews: RealReviewsSyncEngine
7742
7888
  };
7743
7889
  var src_default = LynxSeo;
7890
+ export {
7891
+ validateSeoSlug,
7892
+ resolveFeatureIcon,
7893
+ resolveBuiltInLocations,
7894
+ resolveBrandIcon,
7895
+ renderUiIconSvg,
7896
+ renderBrandIconSvg,
7897
+ getSeoAgentPrompt,
7898
+ src_default as default,
7899
+ createLynxSeoEngine,
7900
+ cleanSeoSlug,
7901
+ YoastParityEngine,
7902
+ VideoYouTubeAnalyzer,
7903
+ UrlyticsEngine,
7904
+ UI_ICONS,
7905
+ TokenQuotaManager,
7906
+ TechnicalRulesAuditor,
7907
+ TeamRbacEngine,
7908
+ SocialVideoSeoAnalyticsEngine,
7909
+ SocialTrendSeoGenerator,
7910
+ SocialGrowthSuite,
7911
+ SocialAdsSocialSeoEngine,
7912
+ SiteAuditor,
7913
+ SerpRankHistoryEngine,
7914
+ SerpClient,
7915
+ SeoOpportunitiesDecayDetector,
7916
+ SchemaGraphBuilder,
7917
+ SUPPORTED_CANONICAL_LOCALES,
7918
+ SCHEMA_LOCAL_BUSINESS_MAP,
7919
+ RssSyndicationFeedGenerator,
7920
+ RealReviewsSyncEngine,
7921
+ RankMathParityEngine,
7922
+ PseoMatrixEngine,
7923
+ PowerWordsPsychologyEngine,
7924
+ PSEO_AGENT_SYSTEM_PROMPT,
7925
+ OgImageGenerator,
7926
+ NGramDensityAnalyzer,
7927
+ McpSeoServerHub,
7928
+ MasterMarketingEngine,
7929
+ MULTILINGUAL_STOP_WORDS,
7930
+ MULTILINGUAL_POWER_WORDS,
7931
+ MULTILINGUAL_DISCLAIMERS,
7932
+ MULTILINGUAL_BANNED_DISPARAGING_WORDS,
7933
+ LynxSeoEngine,
7934
+ LynxSeo,
7935
+ LynxAnalyticsClient,
7936
+ LlmContentCleaner,
7937
+ LegalDisclaimerEngine,
7938
+ LagoTokenMeter,
7939
+ KnowledgeGraphLinker,
7940
+ KeywordPermutatorEngine,
7941
+ IsrCacheManager,
7942
+ InstantMatrixSearchEngine,
7943
+ IndexNowClient,
7944
+ I18nDetector,
7945
+ HyperswitchGateway,
7946
+ GoogleBusinessProfileEngine,
7947
+ GeoMeshLinkingEngine,
7948
+ FreePublicToolsEngine,
7949
+ ExtendedSchemaGraphBuilder,
7950
+ EmbeddableSeoWidgetGenerator,
7951
+ DeepCrawlerAuditor,
7952
+ CrosslinkScorerEngine,
7953
+ CroCopywritingEngine,
7954
+ CopywritingFrameworksMaster,
7955
+ BrandDnaCalendarEngine,
7956
+ BacklinksClient,
7957
+ BUILT_IN_LOCATIONS_DATABASE,
7958
+ BRAND_ICONS,
7959
+ ApiKeyGuardian,
7960
+ AiCopilotClient,
7961
+ AiBotsLogAnalyzer,
7962
+ AdIntelligenceCroEngine
7963
+ };