@lynxflow/seo-engine 1.6.2 β 1.6.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/free-public-tools.d.ts +74 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +177 -6
- package/dist/index.mjs +177 -6
- package/dist/matrix-engine.d.ts +2 -0
- package/package.json +1 -1
- package/src/engine.test.ts +31 -0
- package/src/free-public-tools.ts +224 -0
- package/src/index.ts +1 -0
- package/src/llm-prompt.ts +10 -6
- package/src/matrix-engine.ts +34 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* π οΈ Free Public Interactive Tools & Lead Magnets Suite
|
|
3
|
+
* Inspired by Ahrefs, Semrush, Moz, and WordStream free tool ecosystems.
|
|
4
|
+
*
|
|
5
|
+
* Provides 6 zero-dependency interactive calculators and simulators that can be embedded
|
|
6
|
+
* on public programmatic pages to maximize dwell time, engagement, backlink acquisition, and user conversion.
|
|
7
|
+
*/
|
|
8
|
+
export interface SerpSimulatorResult {
|
|
9
|
+
title: string;
|
|
10
|
+
truncatedTitle: string;
|
|
11
|
+
titlePixelWidth: number;
|
|
12
|
+
isTitleTruncated: boolean;
|
|
13
|
+
description: string;
|
|
14
|
+
truncatedDescription: string;
|
|
15
|
+
isDescriptionTruncated: boolean;
|
|
16
|
+
urlPreview: string;
|
|
17
|
+
estimatedCtrScore: number;
|
|
18
|
+
recommendations: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface RoiCalculatorResult {
|
|
21
|
+
hoursSavedWeekly: number;
|
|
22
|
+
hoursSavedMonthly: number;
|
|
23
|
+
monthlyCostSavings: number;
|
|
24
|
+
annualCostSavings: number;
|
|
25
|
+
roiPercentage: number;
|
|
26
|
+
breakEvenDays: number;
|
|
27
|
+
}
|
|
28
|
+
export interface DensityAnalysisResult {
|
|
29
|
+
totalWords: number;
|
|
30
|
+
characterCount: number;
|
|
31
|
+
readingTimeMinutes: number;
|
|
32
|
+
topKeywords: {
|
|
33
|
+
word: string;
|
|
34
|
+
count: number;
|
|
35
|
+
densityPercent: number;
|
|
36
|
+
}[];
|
|
37
|
+
seoReadabilityScore: number;
|
|
38
|
+
}
|
|
39
|
+
export declare class FreePublicToolsEngine {
|
|
40
|
+
/**
|
|
41
|
+
* 1. Google SERP Preview & CTR Optimizer Simulator (Ahrefs / Moz Parity)
|
|
42
|
+
*/
|
|
43
|
+
static simulateSerpSnippet(input: {
|
|
44
|
+
title: string;
|
|
45
|
+
description: string;
|
|
46
|
+
url: string;
|
|
47
|
+
targetKeyword?: string;
|
|
48
|
+
}): SerpSimulatorResult;
|
|
49
|
+
/**
|
|
50
|
+
* 2. Free ROI & Time-Saved Automation Calculator
|
|
51
|
+
*/
|
|
52
|
+
static calculateRoi(input: {
|
|
53
|
+
hoursSpentPerWeek: number;
|
|
54
|
+
hourlyRateOrSalary: number;
|
|
55
|
+
teamMembersCount?: number;
|
|
56
|
+
softwareMonthlyPrice?: number;
|
|
57
|
+
}): RoiCalculatorResult;
|
|
58
|
+
/**
|
|
59
|
+
* 3. Instant Keyword Density & Readability Analyzer
|
|
60
|
+
*/
|
|
61
|
+
static analyzeTextDensity(text: string, language?: string): DensityAnalysisResult;
|
|
62
|
+
/**
|
|
63
|
+
* 4. Free SEO Slug Cleanser Helper
|
|
64
|
+
*/
|
|
65
|
+
static cleanSlugTool(input: string, lang?: string): {
|
|
66
|
+
original: string;
|
|
67
|
+
cleanSlug: string;
|
|
68
|
+
charSavings: number;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* 5. Free Schema.org Generator Helper
|
|
72
|
+
*/
|
|
73
|
+
static generateSampleSchema(type: "localBusiness" | "softwareApp" | "faq", name: string, url: string): Record<string, unknown>;
|
|
74
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from "./i18n-detector";
|
|
|
18
18
|
export * from "./brand-icons";
|
|
19
19
|
export * from "./ui-icons";
|
|
20
20
|
export * from "./og-image-generator";
|
|
21
|
+
export * from "./free-public-tools";
|
|
21
22
|
export * from "./urlytics-engine";
|
|
22
23
|
export * from "./keyword-permutator";
|
|
23
24
|
export * from "./llm-prompt";
|
package/dist/index.js
CHANGED
|
@@ -92,6 +92,7 @@ __export(exports_src, {
|
|
|
92
92
|
I18nDetector: () => I18nDetector,
|
|
93
93
|
HyperswitchGateway: () => HyperswitchGateway,
|
|
94
94
|
GeoMeshLinkingEngine: () => GeoMeshLinkingEngine,
|
|
95
|
+
FreePublicToolsEngine: () => FreePublicToolsEngine,
|
|
95
96
|
ExtendedSchemaGraphBuilder: () => ExtendedSchemaGraphBuilder,
|
|
96
97
|
EmbeddableSeoWidgetGenerator: () => EmbeddableSeoWidgetGenerator,
|
|
97
98
|
DeepCrawlerAuditor: () => DeepCrawlerAuditor,
|
|
@@ -3926,6 +3927,38 @@ class PseoMatrixEngine {
|
|
|
3926
3927
|
}
|
|
3927
3928
|
if (data.calculators) {
|
|
3928
3929
|
allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
|
|
3930
|
+
} else if (options.enableFreeTools !== false) {
|
|
3931
|
+
const defaultCalculators = [
|
|
3932
|
+
{
|
|
3933
|
+
slug: "serp-preview-simulator",
|
|
3934
|
+
title: "Google SERP Snippet Preview & CTR Simulator",
|
|
3935
|
+
formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
|
|
3936
|
+
savingsMetric: "Search Click-Through Rate",
|
|
3937
|
+
inputs: ["pageTitle", "metaDescription", "targetKeyword"]
|
|
3938
|
+
},
|
|
3939
|
+
{
|
|
3940
|
+
slug: "roi-calculator",
|
|
3941
|
+
title: "Automation ROI & Time-Saved Calculator",
|
|
3942
|
+
formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
|
|
3943
|
+
savingsMetric: "Monthly Net Financial Savings",
|
|
3944
|
+
inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"]
|
|
3945
|
+
},
|
|
3946
|
+
{
|
|
3947
|
+
slug: "seo-slug-generator",
|
|
3948
|
+
title: "SEO URL Slug Cleaner & Optimizer",
|
|
3949
|
+
formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
|
|
3950
|
+
savingsMetric: "URL Cleanliness & Readability",
|
|
3951
|
+
inputs: ["rawTitle", "language"]
|
|
3952
|
+
},
|
|
3953
|
+
{
|
|
3954
|
+
slug: "keyword-density-checker",
|
|
3955
|
+
title: "Live Keyword Density & Readability Analyzer",
|
|
3956
|
+
formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
|
|
3957
|
+
savingsMetric: "Content Optimization Score",
|
|
3958
|
+
inputs: ["articleText"]
|
|
3959
|
+
}
|
|
3960
|
+
];
|
|
3961
|
+
allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
|
|
3929
3962
|
}
|
|
3930
3963
|
for (const p of allPages) {
|
|
3931
3964
|
if (!p.ogImageUrl) {
|
|
@@ -4288,6 +4321,140 @@ function resolveFeatureIcon(featureText) {
|
|
|
4288
4321
|
}
|
|
4289
4322
|
return "zap";
|
|
4290
4323
|
}
|
|
4324
|
+
// src/free-public-tools.ts
|
|
4325
|
+
class FreePublicToolsEngine {
|
|
4326
|
+
static simulateSerpSnippet(input) {
|
|
4327
|
+
const title = (input.title || "").trim();
|
|
4328
|
+
const description = (input.description || "").trim();
|
|
4329
|
+
const url = (input.url || "https://example.com").trim();
|
|
4330
|
+
const kw = (input.targetKeyword || "").toLowerCase().trim();
|
|
4331
|
+
const titlePixelWidth = title.length * 9.5;
|
|
4332
|
+
const maxTitlePixels = 580;
|
|
4333
|
+
const maxDescChars = 158;
|
|
4334
|
+
const isTitleTruncated = titlePixelWidth > maxTitlePixels;
|
|
4335
|
+
const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
|
|
4336
|
+
const isDescriptionTruncated = description.length > maxDescChars;
|
|
4337
|
+
const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
|
|
4338
|
+
let ctrScore = 50;
|
|
4339
|
+
const recommendations = [];
|
|
4340
|
+
if (title.length >= 40 && title.length <= 60) {
|
|
4341
|
+
ctrScore += 20;
|
|
4342
|
+
} else if (title.length < 30) {
|
|
4343
|
+
recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
|
|
4344
|
+
} else if (isTitleTruncated) {
|
|
4345
|
+
ctrScore -= 10;
|
|
4346
|
+
recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
|
|
4347
|
+
}
|
|
4348
|
+
if (kw && title.toLowerCase().includes(kw)) {
|
|
4349
|
+
ctrScore += 15;
|
|
4350
|
+
} else if (kw) {
|
|
4351
|
+
recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
|
|
4352
|
+
}
|
|
4353
|
+
if (description.length >= 120 && description.length <= 158) {
|
|
4354
|
+
ctrScore += 15;
|
|
4355
|
+
} else if (description.length < 80) {
|
|
4356
|
+
recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
|
|
4357
|
+
}
|
|
4358
|
+
return {
|
|
4359
|
+
title,
|
|
4360
|
+
truncatedTitle,
|
|
4361
|
+
titlePixelWidth: Math.round(titlePixelWidth),
|
|
4362
|
+
isTitleTruncated,
|
|
4363
|
+
description,
|
|
4364
|
+
truncatedDescription,
|
|
4365
|
+
isDescriptionTruncated,
|
|
4366
|
+
urlPreview: url,
|
|
4367
|
+
estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
|
|
4368
|
+
recommendations
|
|
4369
|
+
};
|
|
4370
|
+
}
|
|
4371
|
+
static calculateRoi(input) {
|
|
4372
|
+
const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
|
|
4373
|
+
const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
|
|
4374
|
+
const team = Math.max(input.teamMembersCount || 1, 1);
|
|
4375
|
+
const softwareCost = input.softwareMonthlyPrice ?? 49;
|
|
4376
|
+
const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
|
|
4377
|
+
const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
|
|
4378
|
+
const monthlyGrossSavings = hoursSavedMonthly * rate;
|
|
4379
|
+
const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
|
|
4380
|
+
const annualCostSavings = monthlyNetSavings * 12;
|
|
4381
|
+
const roiPercentage = softwareCost > 0 ? Math.round(monthlyNetSavings / softwareCost * 100) : 1000;
|
|
4382
|
+
const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round(softwareCost / (monthlyGrossSavings / 30)), 1) : 30;
|
|
4383
|
+
return {
|
|
4384
|
+
hoursSavedWeekly,
|
|
4385
|
+
hoursSavedMonthly,
|
|
4386
|
+
monthlyCostSavings: Math.round(monthlyNetSavings),
|
|
4387
|
+
annualCostSavings: Math.round(annualCostSavings),
|
|
4388
|
+
roiPercentage,
|
|
4389
|
+
breakEvenDays
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
static analyzeTextDensity(text, language = "fr") {
|
|
4393
|
+
if (!text || typeof text !== "string") {
|
|
4394
|
+
return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
|
|
4395
|
+
}
|
|
4396
|
+
const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
|
|
4397
|
+
const words = clean.split(/\s+/).filter((w) => w.length > 2);
|
|
4398
|
+
const totalWords = words.length;
|
|
4399
|
+
const characterCount = text.length;
|
|
4400
|
+
const readingTimeMinutes = Math.max(Math.round(totalWords / 200 * 10) / 10, 0.5);
|
|
4401
|
+
const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
|
|
4402
|
+
const frequencyMap = new Map;
|
|
4403
|
+
for (const w of words) {
|
|
4404
|
+
if (!stopWords.has(w)) {
|
|
4405
|
+
frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
|
|
4409
|
+
const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
|
|
4410
|
+
word,
|
|
4411
|
+
count,
|
|
4412
|
+
densityPercent: totalWords > 0 ? Math.round(count / totalWords * 1000) / 10 : 0
|
|
4413
|
+
}));
|
|
4414
|
+
let seoReadabilityScore = 70;
|
|
4415
|
+
if (totalWords >= 600)
|
|
4416
|
+
seoReadabilityScore += 20;
|
|
4417
|
+
else if (totalWords < 300)
|
|
4418
|
+
seoReadabilityScore -= 25;
|
|
4419
|
+
return {
|
|
4420
|
+
totalWords,
|
|
4421
|
+
characterCount,
|
|
4422
|
+
readingTimeMinutes,
|
|
4423
|
+
topKeywords,
|
|
4424
|
+
seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100)
|
|
4425
|
+
};
|
|
4426
|
+
}
|
|
4427
|
+
static cleanSlugTool(input, lang = "fr") {
|
|
4428
|
+
const clean = cleanSeoSlug(input, { language: lang });
|
|
4429
|
+
return {
|
|
4430
|
+
original: input,
|
|
4431
|
+
cleanSlug: clean,
|
|
4432
|
+
charSavings: Math.max(input.length - clean.length, 0)
|
|
4433
|
+
};
|
|
4434
|
+
}
|
|
4435
|
+
static generateSampleSchema(type, name, url) {
|
|
4436
|
+
if (type === "localBusiness") {
|
|
4437
|
+
return ExtendedSchemaGraphBuilder.buildLocalBusiness({
|
|
4438
|
+
name,
|
|
4439
|
+
url,
|
|
4440
|
+
city: "Paris",
|
|
4441
|
+
country: "France"
|
|
4442
|
+
});
|
|
4443
|
+
}
|
|
4444
|
+
if (type === "faq") {
|
|
4445
|
+
return ExtendedSchemaGraphBuilder.buildFAQPage([
|
|
4446
|
+
{ question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
|
|
4447
|
+
{ question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` }
|
|
4448
|
+
]);
|
|
4449
|
+
}
|
|
4450
|
+
return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
|
|
4451
|
+
name,
|
|
4452
|
+
description: `Solution logicielle professionnelle ${name}`,
|
|
4453
|
+
url,
|
|
4454
|
+
priceMonthly: 29
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
}
|
|
4291
4458
|
// src/urlytics-engine.ts
|
|
4292
4459
|
class UrlyticsEngine {
|
|
4293
4460
|
static parseUrl(rawUrl) {
|
|
@@ -4706,22 +4873,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
|
4706
4873
|
- \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
|
|
4707
4874
|
- \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
|
|
4708
4875
|
|
|
4709
|
-
7. **\
|
|
4876
|
+
7. **\uD83D\uDEE0οΈ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
|
|
4877
|
+
- Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
|
|
4878
|
+
- Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
|
|
4879
|
+
|
|
4880
|
+
8. **\uD83C\uDFDBοΈ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
4710
4881
|
- \`buildAggregateRating\` (Google Gold Stars 4.9β
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
4711
4882
|
|
|
4712
|
-
|
|
4883
|
+
9. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
4713
4884
|
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
4714
4885
|
|
|
4715
|
-
|
|
4886
|
+
10. **β‘ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
4716
4887
|
- Combinatorial matrix generation: Products Γ Modifiers Γ Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
4717
4888
|
|
|
4718
|
-
|
|
4889
|
+
11. **βοΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
4719
4890
|
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
4720
4891
|
|
|
4721
|
-
|
|
4892
|
+
12. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
4722
4893
|
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
4723
4894
|
|
|
4724
|
-
|
|
4895
|
+
13. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
|
|
4725
4896
|
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
4726
4897
|
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
4727
4898
|
`.trim();
|
package/dist/index.mjs
CHANGED
|
@@ -3815,6 +3815,38 @@ class PseoMatrixEngine {
|
|
|
3815
3815
|
}
|
|
3816
3816
|
if (data.calculators) {
|
|
3817
3817
|
allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
|
|
3818
|
+
} else if (options.enableFreeTools !== false) {
|
|
3819
|
+
const defaultCalculators = [
|
|
3820
|
+
{
|
|
3821
|
+
slug: "serp-preview-simulator",
|
|
3822
|
+
title: "Google SERP Snippet Preview & CTR Simulator",
|
|
3823
|
+
formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
|
|
3824
|
+
savingsMetric: "Search Click-Through Rate",
|
|
3825
|
+
inputs: ["pageTitle", "metaDescription", "targetKeyword"]
|
|
3826
|
+
},
|
|
3827
|
+
{
|
|
3828
|
+
slug: "roi-calculator",
|
|
3829
|
+
title: "Automation ROI & Time-Saved Calculator",
|
|
3830
|
+
formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
|
|
3831
|
+
savingsMetric: "Monthly Net Financial Savings",
|
|
3832
|
+
inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"]
|
|
3833
|
+
},
|
|
3834
|
+
{
|
|
3835
|
+
slug: "seo-slug-generator",
|
|
3836
|
+
title: "SEO URL Slug Cleaner & Optimizer",
|
|
3837
|
+
formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
|
|
3838
|
+
savingsMetric: "URL Cleanliness & Readability",
|
|
3839
|
+
inputs: ["rawTitle", "language"]
|
|
3840
|
+
},
|
|
3841
|
+
{
|
|
3842
|
+
slug: "keyword-density-checker",
|
|
3843
|
+
title: "Live Keyword Density & Readability Analyzer",
|
|
3844
|
+
formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
|
|
3845
|
+
savingsMetric: "Content Optimization Score",
|
|
3846
|
+
inputs: ["articleText"]
|
|
3847
|
+
}
|
|
3848
|
+
];
|
|
3849
|
+
allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
|
|
3818
3850
|
}
|
|
3819
3851
|
for (const p of allPages) {
|
|
3820
3852
|
if (!p.ogImageUrl) {
|
|
@@ -4177,6 +4209,140 @@ function resolveFeatureIcon(featureText) {
|
|
|
4177
4209
|
}
|
|
4178
4210
|
return "zap";
|
|
4179
4211
|
}
|
|
4212
|
+
// src/free-public-tools.ts
|
|
4213
|
+
class FreePublicToolsEngine {
|
|
4214
|
+
static simulateSerpSnippet(input) {
|
|
4215
|
+
const title = (input.title || "").trim();
|
|
4216
|
+
const description = (input.description || "").trim();
|
|
4217
|
+
const url = (input.url || "https://example.com").trim();
|
|
4218
|
+
const kw = (input.targetKeyword || "").toLowerCase().trim();
|
|
4219
|
+
const titlePixelWidth = title.length * 9.5;
|
|
4220
|
+
const maxTitlePixels = 580;
|
|
4221
|
+
const maxDescChars = 158;
|
|
4222
|
+
const isTitleTruncated = titlePixelWidth > maxTitlePixels;
|
|
4223
|
+
const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
|
|
4224
|
+
const isDescriptionTruncated = description.length > maxDescChars;
|
|
4225
|
+
const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
|
|
4226
|
+
let ctrScore = 50;
|
|
4227
|
+
const recommendations = [];
|
|
4228
|
+
if (title.length >= 40 && title.length <= 60) {
|
|
4229
|
+
ctrScore += 20;
|
|
4230
|
+
} else if (title.length < 30) {
|
|
4231
|
+
recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
|
|
4232
|
+
} else if (isTitleTruncated) {
|
|
4233
|
+
ctrScore -= 10;
|
|
4234
|
+
recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
|
|
4235
|
+
}
|
|
4236
|
+
if (kw && title.toLowerCase().includes(kw)) {
|
|
4237
|
+
ctrScore += 15;
|
|
4238
|
+
} else if (kw) {
|
|
4239
|
+
recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
|
|
4240
|
+
}
|
|
4241
|
+
if (description.length >= 120 && description.length <= 158) {
|
|
4242
|
+
ctrScore += 15;
|
|
4243
|
+
} else if (description.length < 80) {
|
|
4244
|
+
recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
|
|
4245
|
+
}
|
|
4246
|
+
return {
|
|
4247
|
+
title,
|
|
4248
|
+
truncatedTitle,
|
|
4249
|
+
titlePixelWidth: Math.round(titlePixelWidth),
|
|
4250
|
+
isTitleTruncated,
|
|
4251
|
+
description,
|
|
4252
|
+
truncatedDescription,
|
|
4253
|
+
isDescriptionTruncated,
|
|
4254
|
+
urlPreview: url,
|
|
4255
|
+
estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
|
|
4256
|
+
recommendations
|
|
4257
|
+
};
|
|
4258
|
+
}
|
|
4259
|
+
static calculateRoi(input) {
|
|
4260
|
+
const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
|
|
4261
|
+
const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
|
|
4262
|
+
const team = Math.max(input.teamMembersCount || 1, 1);
|
|
4263
|
+
const softwareCost = input.softwareMonthlyPrice ?? 49;
|
|
4264
|
+
const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
|
|
4265
|
+
const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
|
|
4266
|
+
const monthlyGrossSavings = hoursSavedMonthly * rate;
|
|
4267
|
+
const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
|
|
4268
|
+
const annualCostSavings = monthlyNetSavings * 12;
|
|
4269
|
+
const roiPercentage = softwareCost > 0 ? Math.round(monthlyNetSavings / softwareCost * 100) : 1000;
|
|
4270
|
+
const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round(softwareCost / (monthlyGrossSavings / 30)), 1) : 30;
|
|
4271
|
+
return {
|
|
4272
|
+
hoursSavedWeekly,
|
|
4273
|
+
hoursSavedMonthly,
|
|
4274
|
+
monthlyCostSavings: Math.round(monthlyNetSavings),
|
|
4275
|
+
annualCostSavings: Math.round(annualCostSavings),
|
|
4276
|
+
roiPercentage,
|
|
4277
|
+
breakEvenDays
|
|
4278
|
+
};
|
|
4279
|
+
}
|
|
4280
|
+
static analyzeTextDensity(text, language = "fr") {
|
|
4281
|
+
if (!text || typeof text !== "string") {
|
|
4282
|
+
return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
|
|
4283
|
+
}
|
|
4284
|
+
const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
|
|
4285
|
+
const words = clean.split(/\s+/).filter((w) => w.length > 2);
|
|
4286
|
+
const totalWords = words.length;
|
|
4287
|
+
const characterCount = text.length;
|
|
4288
|
+
const readingTimeMinutes = Math.max(Math.round(totalWords / 200 * 10) / 10, 0.5);
|
|
4289
|
+
const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
|
|
4290
|
+
const frequencyMap = new Map;
|
|
4291
|
+
for (const w of words) {
|
|
4292
|
+
if (!stopWords.has(w)) {
|
|
4293
|
+
frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
|
|
4297
|
+
const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
|
|
4298
|
+
word,
|
|
4299
|
+
count,
|
|
4300
|
+
densityPercent: totalWords > 0 ? Math.round(count / totalWords * 1000) / 10 : 0
|
|
4301
|
+
}));
|
|
4302
|
+
let seoReadabilityScore = 70;
|
|
4303
|
+
if (totalWords >= 600)
|
|
4304
|
+
seoReadabilityScore += 20;
|
|
4305
|
+
else if (totalWords < 300)
|
|
4306
|
+
seoReadabilityScore -= 25;
|
|
4307
|
+
return {
|
|
4308
|
+
totalWords,
|
|
4309
|
+
characterCount,
|
|
4310
|
+
readingTimeMinutes,
|
|
4311
|
+
topKeywords,
|
|
4312
|
+
seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100)
|
|
4313
|
+
};
|
|
4314
|
+
}
|
|
4315
|
+
static cleanSlugTool(input, lang = "fr") {
|
|
4316
|
+
const clean = cleanSeoSlug(input, { language: lang });
|
|
4317
|
+
return {
|
|
4318
|
+
original: input,
|
|
4319
|
+
cleanSlug: clean,
|
|
4320
|
+
charSavings: Math.max(input.length - clean.length, 0)
|
|
4321
|
+
};
|
|
4322
|
+
}
|
|
4323
|
+
static generateSampleSchema(type, name, url) {
|
|
4324
|
+
if (type === "localBusiness") {
|
|
4325
|
+
return ExtendedSchemaGraphBuilder.buildLocalBusiness({
|
|
4326
|
+
name,
|
|
4327
|
+
url,
|
|
4328
|
+
city: "Paris",
|
|
4329
|
+
country: "France"
|
|
4330
|
+
});
|
|
4331
|
+
}
|
|
4332
|
+
if (type === "faq") {
|
|
4333
|
+
return ExtendedSchemaGraphBuilder.buildFAQPage([
|
|
4334
|
+
{ question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
|
|
4335
|
+
{ question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` }
|
|
4336
|
+
]);
|
|
4337
|
+
}
|
|
4338
|
+
return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
|
|
4339
|
+
name,
|
|
4340
|
+
description: `Solution logicielle professionnelle ${name}`,
|
|
4341
|
+
url,
|
|
4342
|
+
priceMonthly: 29
|
|
4343
|
+
});
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4180
4346
|
// src/urlytics-engine.ts
|
|
4181
4347
|
class UrlyticsEngine {
|
|
4182
4348
|
static parseUrl(rawUrl) {
|
|
@@ -4595,22 +4761,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
|
4595
4761
|
- \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
|
|
4596
4762
|
- \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
|
|
4597
4763
|
|
|
4598
|
-
7. **\
|
|
4764
|
+
7. **\uD83D\uDEE0οΈ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
|
|
4765
|
+
- Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
|
|
4766
|
+
- Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
|
|
4767
|
+
|
|
4768
|
+
8. **\uD83C\uDFDBοΈ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
4599
4769
|
- \`buildAggregateRating\` (Google Gold Stars 4.9β
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
4600
4770
|
|
|
4601
|
-
|
|
4771
|
+
9. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
4602
4772
|
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
4603
4773
|
|
|
4604
|
-
|
|
4774
|
+
10. **β‘ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
4605
4775
|
- Combinatorial matrix generation: Products Γ Modifiers Γ Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
4606
4776
|
|
|
4607
|
-
|
|
4777
|
+
11. **βοΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
4608
4778
|
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
4609
4779
|
|
|
4610
|
-
|
|
4780
|
+
12. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
4611
4781
|
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
4612
4782
|
|
|
4613
|
-
|
|
4783
|
+
13. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
|
|
4614
4784
|
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
4615
4785
|
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
4616
4786
|
`.trim();
|
|
@@ -6811,6 +6981,7 @@ export {
|
|
|
6811
6981
|
I18nDetector,
|
|
6812
6982
|
HyperswitchGateway,
|
|
6813
6983
|
GeoMeshLinkingEngine,
|
|
6984
|
+
FreePublicToolsEngine,
|
|
6814
6985
|
ExtendedSchemaGraphBuilder,
|
|
6815
6986
|
EmbeddableSeoWidgetGenerator,
|
|
6816
6987
|
DeepCrawlerAuditor,
|
package/dist/matrix-engine.d.ts
CHANGED
|
@@ -95,6 +95,7 @@ export interface PseoCalculator {
|
|
|
95
95
|
title: string;
|
|
96
96
|
formulaDescription: string;
|
|
97
97
|
savingsMetric: string;
|
|
98
|
+
inputs?: string[];
|
|
98
99
|
}
|
|
99
100
|
export interface SchemaOrgGraph {
|
|
100
101
|
"@context": "https://schema.org";
|
|
@@ -132,6 +133,7 @@ export interface MatrixOptions {
|
|
|
132
133
|
countries?: string[] | string;
|
|
133
134
|
territories?: string[] | string;
|
|
134
135
|
cleanDirectRoutes?: boolean;
|
|
136
|
+
enableFreeTools?: boolean;
|
|
135
137
|
minPopulationToIndex?: number;
|
|
136
138
|
defaultCurrency?: string;
|
|
137
139
|
defaultCurrencySymbol?: string;
|
package/package.json
CHANGED
package/src/engine.test.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { renderBrandIconSvg } from "./brand-icons";
|
|
|
10
10
|
import { I18nDetector } from "./i18n-detector";
|
|
11
11
|
import { renderUiIconSvg, resolveFeatureIcon } from "./ui-icons";
|
|
12
12
|
import { OgImageGenerator } from "./og-image-generator";
|
|
13
|
+
import { FreePublicToolsEngine } from "./free-public-tools";
|
|
13
14
|
|
|
14
15
|
describe("Multilingual SEO Slug Engine (10+ Languages)", () => {
|
|
15
16
|
it("English: Strips stop words and years", () => {
|
|
@@ -306,4 +307,34 @@ describe("Audited Reference Engines (Advertools, Santifer, Seonaut)", () => {
|
|
|
306
307
|
expect(page?.ogImageUrl).toContain("/api/og?");
|
|
307
308
|
expect(page?.ogImageUrl).toContain("brand=Acme");
|
|
308
309
|
});
|
|
310
|
+
|
|
311
|
+
it("FreePublicToolsEngine: Simulates SERP, calculates ROI, and analyzes density", () => {
|
|
312
|
+
const serp = FreePublicToolsEngine.simulateSerpSnippet({
|
|
313
|
+
title: "Autopost Facebook & Instagram Tool 2026",
|
|
314
|
+
description: "Automate your social media scheduling across all major networks with AI copilot and analytics.",
|
|
315
|
+
url: "https://acme.com/autopost-facebook",
|
|
316
|
+
targetKeyword: "autopost",
|
|
317
|
+
});
|
|
318
|
+
expect(serp.estimatedCtrScore).toBeGreaterThan(50);
|
|
319
|
+
expect(serp.titlePixelWidth).toBeGreaterThan(0);
|
|
320
|
+
|
|
321
|
+
const roi = FreePublicToolsEngine.calculateRoi({
|
|
322
|
+
hoursSpentPerWeek: 10,
|
|
323
|
+
hourlyRateOrSalary: 50,
|
|
324
|
+
teamMembersCount: 2,
|
|
325
|
+
softwareMonthlyPrice: 79,
|
|
326
|
+
});
|
|
327
|
+
expect(roi.monthlyCostSavings).toBeGreaterThan(1000);
|
|
328
|
+
expect(roi.roiPercentage).toBeGreaterThan(100);
|
|
329
|
+
|
|
330
|
+
const density = FreePublicToolsEngine.analyzeTextDensity(
|
|
331
|
+
"Autopost Facebook automatise vos rΓ©seaux sociaux. Notre outil autopost vous fait gagner du temps avec autopost.",
|
|
332
|
+
"fr",
|
|
333
|
+
);
|
|
334
|
+
expect(density.totalWords).toBeGreaterThan(5);
|
|
335
|
+
expect(density.topKeywords[0].word).toBe("autopost");
|
|
336
|
+
|
|
337
|
+
const schema = FreePublicToolsEngine.generateSampleSchema("softwareApp", "Acme", "https://acme.com");
|
|
338
|
+
expect(schema["@type"]).toBe("SoftwareApplication");
|
|
339
|
+
});
|
|
309
340
|
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* π οΈ Free Public Interactive Tools & Lead Magnets Suite
|
|
3
|
+
* Inspired by Ahrefs, Semrush, Moz, and WordStream free tool ecosystems.
|
|
4
|
+
*
|
|
5
|
+
* Provides 6 zero-dependency interactive calculators and simulators that can be embedded
|
|
6
|
+
* on public programmatic pages to maximize dwell time, engagement, backlink acquisition, and user conversion.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { cleanSeoSlug } from "./slug-engine";
|
|
10
|
+
import { ExtendedSchemaGraphBuilder } from "./extended-schemas";
|
|
11
|
+
|
|
12
|
+
export interface SerpSimulatorResult {
|
|
13
|
+
title: string;
|
|
14
|
+
truncatedTitle: string;
|
|
15
|
+
titlePixelWidth: number;
|
|
16
|
+
isTitleTruncated: boolean;
|
|
17
|
+
description: string;
|
|
18
|
+
truncatedDescription: string;
|
|
19
|
+
isDescriptionTruncated: boolean;
|
|
20
|
+
urlPreview: string;
|
|
21
|
+
estimatedCtrScore: number; // 0 to 100
|
|
22
|
+
recommendations: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RoiCalculatorResult {
|
|
26
|
+
hoursSavedWeekly: number;
|
|
27
|
+
hoursSavedMonthly: number;
|
|
28
|
+
monthlyCostSavings: number;
|
|
29
|
+
annualCostSavings: number;
|
|
30
|
+
roiPercentage: number;
|
|
31
|
+
breakEvenDays: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface DensityAnalysisResult {
|
|
35
|
+
totalWords: number;
|
|
36
|
+
characterCount: number;
|
|
37
|
+
readingTimeMinutes: number;
|
|
38
|
+
topKeywords: { word: string; count: number; densityPercent: number }[];
|
|
39
|
+
seoReadabilityScore: number; // 0 to 100
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class FreePublicToolsEngine {
|
|
43
|
+
/**
|
|
44
|
+
* 1. Google SERP Preview & CTR Optimizer Simulator (Ahrefs / Moz Parity)
|
|
45
|
+
*/
|
|
46
|
+
static simulateSerpSnippet(input: {
|
|
47
|
+
title: string;
|
|
48
|
+
description: string;
|
|
49
|
+
url: string;
|
|
50
|
+
targetKeyword?: string;
|
|
51
|
+
}): SerpSimulatorResult {
|
|
52
|
+
const title = (input.title || "").trim();
|
|
53
|
+
const description = (input.description || "").trim();
|
|
54
|
+
const url = (input.url || "https://example.com").trim();
|
|
55
|
+
const kw = (input.targetKeyword || "").toLowerCase().trim();
|
|
56
|
+
|
|
57
|
+
// Average pixel width estimation (approx 10px per char on Arial 20px)
|
|
58
|
+
const titlePixelWidth = title.length * 9.5;
|
|
59
|
+
const maxTitlePixels = 580; // Google Desktop breakpoint
|
|
60
|
+
const maxDescChars = 158;
|
|
61
|
+
|
|
62
|
+
const isTitleTruncated = titlePixelWidth > maxTitlePixels;
|
|
63
|
+
const truncatedTitle = isTitleTruncated ? title.slice(0, 56) + "..." : title;
|
|
64
|
+
|
|
65
|
+
const isDescriptionTruncated = description.length > maxDescChars;
|
|
66
|
+
const truncatedDescription = isDescriptionTruncated ? description.slice(0, 155) + "..." : description;
|
|
67
|
+
|
|
68
|
+
let ctrScore = 50;
|
|
69
|
+
const recommendations: string[] = [];
|
|
70
|
+
|
|
71
|
+
// Title checks
|
|
72
|
+
if (title.length >= 40 && title.length <= 60) {
|
|
73
|
+
ctrScore += 20;
|
|
74
|
+
} else if (title.length < 30) {
|
|
75
|
+
recommendations.push("Le titre est trop court (< 30 car.). Ajoutez des prΓ©cisions pour booster le clic.");
|
|
76
|
+
} else if (isTitleTruncated) {
|
|
77
|
+
ctrScore -= 10;
|
|
78
|
+
recommendations.push("Le titre dΓ©passe 580px et sera tronquΓ© sur Google Desktop.");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Keyword presence
|
|
82
|
+
if (kw && title.toLowerCase().includes(kw)) {
|
|
83
|
+
ctrScore += 15;
|
|
84
|
+
} else if (kw) {
|
|
85
|
+
recommendations.push(`Le mot-clΓ© principal "${kw}" est absent du titre.`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Description checks
|
|
89
|
+
if (description.length >= 120 && description.length <= 158) {
|
|
90
|
+
ctrScore += 15;
|
|
91
|
+
} else if (description.length < 80) {
|
|
92
|
+
recommendations.push("La mΓ©ta-description est trop courte (< 80 car.).");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
title,
|
|
97
|
+
truncatedTitle,
|
|
98
|
+
titlePixelWidth: Math.round(titlePixelWidth),
|
|
99
|
+
isTitleTruncated,
|
|
100
|
+
description,
|
|
101
|
+
truncatedDescription,
|
|
102
|
+
isDescriptionTruncated,
|
|
103
|
+
urlPreview: url,
|
|
104
|
+
estimatedCtrScore: Math.min(Math.max(ctrScore, 10), 100),
|
|
105
|
+
recommendations,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 2. Free ROI & Time-Saved Automation Calculator
|
|
111
|
+
*/
|
|
112
|
+
static calculateRoi(input: {
|
|
113
|
+
hoursSpentPerWeek: number;
|
|
114
|
+
hourlyRateOrSalary: number;
|
|
115
|
+
teamMembersCount?: number;
|
|
116
|
+
softwareMonthlyPrice?: number;
|
|
117
|
+
}): RoiCalculatorResult {
|
|
118
|
+
const hours = Math.max(input.hoursSpentPerWeek || 5, 1);
|
|
119
|
+
const rate = Math.max(input.hourlyRateOrSalary || 35, 1);
|
|
120
|
+
const team = Math.max(input.teamMembersCount || 1, 1);
|
|
121
|
+
const softwareCost = input.softwareMonthlyPrice ?? 49;
|
|
122
|
+
|
|
123
|
+
// Assuming automation saves ~75% of manual operational time
|
|
124
|
+
const hoursSavedWeekly = Math.round(hours * 0.75 * team * 10) / 10;
|
|
125
|
+
const hoursSavedMonthly = Math.round(hoursSavedWeekly * 4.33);
|
|
126
|
+
|
|
127
|
+
const monthlyGrossSavings = hoursSavedMonthly * rate;
|
|
128
|
+
const monthlyNetSavings = Math.max(monthlyGrossSavings - softwareCost, 0);
|
|
129
|
+
const annualCostSavings = monthlyNetSavings * 12;
|
|
130
|
+
|
|
131
|
+
const roiPercentage = softwareCost > 0 ? Math.round((monthlyNetSavings / softwareCost) * 100) : 1000;
|
|
132
|
+
const breakEvenDays = monthlyGrossSavings > 0 ? Math.max(Math.round((softwareCost / (monthlyGrossSavings / 30))), 1) : 30;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
hoursSavedWeekly,
|
|
136
|
+
hoursSavedMonthly,
|
|
137
|
+
monthlyCostSavings: Math.round(monthlyNetSavings),
|
|
138
|
+
annualCostSavings: Math.round(annualCostSavings),
|
|
139
|
+
roiPercentage,
|
|
140
|
+
breakEvenDays,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 3. Instant Keyword Density & Readability Analyzer
|
|
146
|
+
*/
|
|
147
|
+
static analyzeTextDensity(text: string, language: string = "fr"): DensityAnalysisResult {
|
|
148
|
+
if (!text || typeof text !== "string") {
|
|
149
|
+
return { totalWords: 0, characterCount: 0, readingTimeMinutes: 0, topKeywords: [], seoReadabilityScore: 0 };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const clean = text.toLowerCase().replace(/[^a-z0-9Γ -ΓΏ\s]/g, " ");
|
|
153
|
+
const words = clean.split(/\s+/).filter((w) => w.length > 2);
|
|
154
|
+
const totalWords = words.length;
|
|
155
|
+
const characterCount = text.length;
|
|
156
|
+
const readingTimeMinutes = Math.max(Math.round((totalWords / 200) * 10) / 10, 0.5);
|
|
157
|
+
|
|
158
|
+
const stopWords = new Set(["pour", "dans", "avec", "sur", "les", "des", "une", "que", "qui", "est", "par", "the", "and", "for", "with", "this", "that"]);
|
|
159
|
+
const frequencyMap = new Map<string, number>();
|
|
160
|
+
|
|
161
|
+
for (const w of words) {
|
|
162
|
+
if (!stopWords.has(w)) {
|
|
163
|
+
frequencyMap.set(w, (frequencyMap.get(w) || 0) + 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const sorted = Array.from(frequencyMap.entries()).sort((a, b) => b[1] - a[1]);
|
|
168
|
+
const topKeywords = sorted.slice(0, 8).map(([word, count]) => ({
|
|
169
|
+
word,
|
|
170
|
+
count,
|
|
171
|
+
densityPercent: totalWords > 0 ? Math.round((count / totalWords) * 1000) / 10 : 0,
|
|
172
|
+
}));
|
|
173
|
+
|
|
174
|
+
let seoReadabilityScore = 70;
|
|
175
|
+
if (totalWords >= 600) seoReadabilityScore += 20;
|
|
176
|
+
else if (totalWords < 300) seoReadabilityScore -= 25;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
totalWords,
|
|
180
|
+
characterCount,
|
|
181
|
+
readingTimeMinutes,
|
|
182
|
+
topKeywords,
|
|
183
|
+
seoReadabilityScore: Math.min(Math.max(seoReadabilityScore, 10), 100),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 4. Free SEO Slug Cleanser Helper
|
|
189
|
+
*/
|
|
190
|
+
static cleanSlugTool(input: string, lang: string = "fr"): { original: string; cleanSlug: string; charSavings: number } {
|
|
191
|
+
const clean = cleanSeoSlug(input, { language: lang });
|
|
192
|
+
return {
|
|
193
|
+
original: input,
|
|
194
|
+
cleanSlug: clean,
|
|
195
|
+
charSavings: Math.max(input.length - clean.length, 0),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 5. Free Schema.org Generator Helper
|
|
201
|
+
*/
|
|
202
|
+
static generateSampleSchema(type: "localBusiness" | "softwareApp" | "faq", name: string, url: string): Record<string, unknown> {
|
|
203
|
+
if (type === "localBusiness") {
|
|
204
|
+
return ExtendedSchemaGraphBuilder.buildLocalBusiness({
|
|
205
|
+
name,
|
|
206
|
+
url,
|
|
207
|
+
city: "Paris",
|
|
208
|
+
country: "France",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (type === "faq") {
|
|
212
|
+
return ExtendedSchemaGraphBuilder.buildFAQPage([
|
|
213
|
+
{ question: `Comment fonctionne ${name} ?`, answer: `${name} automatise vos opΓ©rations en quelques clics.` },
|
|
214
|
+
{ question: `Quel est le tarif de ${name} ?`, answer: `Un essai gratuit de 14 jours est disponible sans carte bancaire.` },
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
return ExtendedSchemaGraphBuilder.buildSoftwareApplication({
|
|
218
|
+
name,
|
|
219
|
+
description: `Solution logicielle professionnelle ${name}`,
|
|
220
|
+
url,
|
|
221
|
+
priceMonthly: 29,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from "./i18n-detector";
|
|
|
19
19
|
export * from "./brand-icons";
|
|
20
20
|
export * from "./ui-icons";
|
|
21
21
|
export * from "./og-image-generator";
|
|
22
|
+
export * from "./free-public-tools";
|
|
22
23
|
export * from "./urlytics-engine";
|
|
23
24
|
export * from "./keyword-permutator";
|
|
24
25
|
export * from "./llm-prompt";
|
package/src/llm-prompt.ts
CHANGED
|
@@ -283,22 +283,26 @@ The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
|
283
283
|
- \`renderDynamicOgSvg(opts)\`: Generates high-converting 1200x630 SVG social cards with glassmorphism badges, star ratings, and gradient backdrops.
|
|
284
284
|
- \`generateOgImageUrl(domain, pageMeta, brandName)\`: Edge-ready query URL for \`app/api/og/route.ts\`.
|
|
285
285
|
|
|
286
|
-
7.
|
|
286
|
+
7. **π οΈ Free Public Interactive Tools & Lead Magnets (\`FreePublicToolsEngine\`):**
|
|
287
|
+
- Ahrefs/Semrush-style high-intent public calculators: Google SERP Preview Simulator, Automation ROI Calculator, Keyword Density Analyzer, and Schema.org Generator.
|
|
288
|
+
- Boosts dwell time, organic backlinks, and visitor-to-customer conversion.
|
|
289
|
+
|
|
290
|
+
8. **ποΈ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
287
291
|
- \`buildAggregateRating\` (Google Gold Stars 4.9β
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
288
292
|
|
|
289
|
-
|
|
293
|
+
9. **π URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
290
294
|
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
291
295
|
|
|
292
|
-
|
|
296
|
+
10. **β‘ SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
293
297
|
- Combinatorial matrix generation: Products Γ Modifiers Γ Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
294
298
|
|
|
295
|
-
|
|
299
|
+
11. **βοΈ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
296
300
|
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
297
301
|
|
|
298
|
-
|
|
302
|
+
12. **π Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
299
303
|
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
300
304
|
|
|
301
|
-
|
|
305
|
+
13. **π§Ή URL Slug Engine & Schema.org Graphs:**
|
|
302
306
|
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
303
307
|
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
304
308
|
`.trim();
|
package/src/matrix-engine.ts
CHANGED
|
@@ -125,6 +125,7 @@ export interface PseoCalculator {
|
|
|
125
125
|
title: string;
|
|
126
126
|
formulaDescription: string;
|
|
127
127
|
savingsMetric: string;
|
|
128
|
+
inputs?: string[];
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
export interface SchemaOrgGraph {
|
|
@@ -162,6 +163,7 @@ export interface MatrixOptions {
|
|
|
162
163
|
countries?: string[] | string; // e.g. ["france", "spain"] or "europe" or "international"
|
|
163
164
|
territories?: string[] | string; // Alias for countries
|
|
164
165
|
cleanDirectRoutes?: boolean; // When true (default), eliminates parasite words (/solutions/, etc.) for direct /{service}/{city}
|
|
166
|
+
enableFreeTools?: boolean; // When true (default), auto-generates 5 high-converting interactive tools like Ahrefs
|
|
165
167
|
minPopulationToIndex?: number;
|
|
166
168
|
defaultCurrency?: string;
|
|
167
169
|
defaultCurrencySymbol?: string;
|
|
@@ -824,6 +826,38 @@ export class PseoMatrixEngine {
|
|
|
824
826
|
}
|
|
825
827
|
if (data.calculators) {
|
|
826
828
|
allPages.push(...this.generateCalculatorMatrix(domain, data.calculators, options));
|
|
829
|
+
} else if (options.enableFreeTools !== false) {
|
|
830
|
+
const defaultCalculators: PseoCalculator[] = [
|
|
831
|
+
{
|
|
832
|
+
slug: "serp-preview-simulator",
|
|
833
|
+
title: "Google SERP Snippet Preview & CTR Simulator",
|
|
834
|
+
formulaDescription: "Simulate desktop and mobile Google search appearance and optimize CTR",
|
|
835
|
+
savingsMetric: "Search Click-Through Rate",
|
|
836
|
+
inputs: ["pageTitle", "metaDescription", "targetKeyword"],
|
|
837
|
+
},
|
|
838
|
+
{
|
|
839
|
+
slug: "roi-calculator",
|
|
840
|
+
title: "Automation ROI & Time-Saved Calculator",
|
|
841
|
+
formulaDescription: "Calculate weekly operational hours recovered and monthly budget saved",
|
|
842
|
+
savingsMetric: "Monthly Net Financial Savings",
|
|
843
|
+
inputs: ["hoursSpentWeekly", "hourlyRate", "teamMembers"],
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
slug: "seo-slug-generator",
|
|
847
|
+
title: "SEO URL Slug Cleaner & Optimizer",
|
|
848
|
+
formulaDescription: "Strip stop words, dates, and noise characters for high-CTR clean URLs",
|
|
849
|
+
savingsMetric: "URL Cleanliness & Readability",
|
|
850
|
+
inputs: ["rawTitle", "language"],
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
slug: "keyword-density-checker",
|
|
854
|
+
title: "Live Keyword Density & Readability Analyzer",
|
|
855
|
+
formulaDescription: "Analyze n-gram frequency, reading time, and content depth",
|
|
856
|
+
savingsMetric: "Content Optimization Score",
|
|
857
|
+
inputs: ["articleText"],
|
|
858
|
+
},
|
|
859
|
+
];
|
|
860
|
+
allPages.push(...this.generateCalculatorMatrix(domain, defaultCalculators, options));
|
|
827
861
|
}
|
|
828
862
|
|
|
829
863
|
for (const p of allPages) {
|