@lynxflow/seo-engine 1.5.9 โ 1.6.1
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/i18n-detector.d.ts +24 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +150 -39
- package/dist/index.mjs +150 -39
- package/dist/matrix-engine.d.ts +27 -0
- package/package.json +1 -1
- package/src/engine.test.ts +31 -0
- package/src/i18n-detector.ts +70 -0
- package/src/index.ts +1 -0
- package/src/llm-prompt.ts +60 -41
- package/src/matrix-engine.ts +85 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ๐ Dynamic i18n & Locale Auto-Detector
|
|
3
|
+
* Automatically detects and synchronizes website locales without requiring hardcoded lists.
|
|
4
|
+
* Compatible with next-intl, next-i18next, i18next, Paraglide, and Astro i18n.
|
|
5
|
+
*/
|
|
6
|
+
export declare const SUPPORTED_CANONICAL_LOCALES: readonly ["en", "fr", "es", "de", "it", "pt", "nl", "ru", "sv", "pl", "ja", "zh", "ar"];
|
|
7
|
+
export type SupportedLocale = (typeof SUPPORTED_CANONICAL_LOCALES)[number];
|
|
8
|
+
export declare class I18nDetector {
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a clean 2-letter ISO language code from any locale string (e.g. "fr-FR" -> "fr").
|
|
11
|
+
*/
|
|
12
|
+
static normalizeLocale(localeInput?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Auto-detects and extracts active locales from common environment variables or array inputs.
|
|
15
|
+
*/
|
|
16
|
+
static resolveActiveLocales(explicitLocales?: string[] | string): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Matches whether a given path segment is a language prefix (e.g. "/fr/autopost-facebook/paris").
|
|
19
|
+
*/
|
|
20
|
+
static extractLocaleFromPath(pathname: string, activeLocales: string[]): {
|
|
21
|
+
locale: string;
|
|
22
|
+
remainingPath: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./slug-engine";
|
|
|
14
14
|
export * from "./legal-disclaimers";
|
|
15
15
|
export * from "./matrix-engine";
|
|
16
16
|
export * from "./built-in-locations";
|
|
17
|
+
export * from "./i18n-detector";
|
|
17
18
|
export * from "./brand-icons";
|
|
18
19
|
export * from "./urlytics-engine";
|
|
19
20
|
export * from "./keyword-permutator";
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ __export(exports_src, {
|
|
|
61
61
|
SerpClient: () => SerpClient,
|
|
62
62
|
SeoOpportunitiesDecayDetector: () => SeoOpportunitiesDecayDetector,
|
|
63
63
|
SchemaGraphBuilder: () => SchemaGraphBuilder,
|
|
64
|
+
SUPPORTED_CANONICAL_LOCALES: () => SUPPORTED_CANONICAL_LOCALES,
|
|
64
65
|
SCHEMA_LOCAL_BUSINESS_MAP: () => SCHEMA_LOCAL_BUSINESS_MAP,
|
|
65
66
|
RssSyndicationFeedGenerator: () => RssSyndicationFeedGenerator,
|
|
66
67
|
RealReviewsSyncEngine: () => RealReviewsSyncEngine,
|
|
@@ -84,6 +85,7 @@ __export(exports_src, {
|
|
|
84
85
|
IsrCacheManager: () => IsrCacheManager,
|
|
85
86
|
InstantMatrixSearchEngine: () => InstantMatrixSearchEngine,
|
|
86
87
|
IndexNowClient: () => IndexNowClient,
|
|
88
|
+
I18nDetector: () => I18nDetector,
|
|
87
89
|
HyperswitchGateway: () => HyperswitchGateway,
|
|
88
90
|
GeoMeshLinkingEngine: () => GeoMeshLinkingEngine,
|
|
89
91
|
ExtendedSchemaGraphBuilder: () => ExtendedSchemaGraphBuilder,
|
|
@@ -3862,6 +3864,11 @@ class PseoMatrixEngine {
|
|
|
3862
3864
|
${urls}
|
|
3863
3865
|
</urlset>`;
|
|
3864
3866
|
}
|
|
3867
|
+
resolveServicePage(serviceSlug, citySlug, domain, data, options) {
|
|
3868
|
+
const cleanService = cleanSeoSlug(serviceSlug, { language: options.language });
|
|
3869
|
+
const cleanCity = cleanSeoSlug(citySlug, { language: options.language });
|
|
3870
|
+
return this.resolvePage([cleanService, cleanCity], domain, data, options);
|
|
3871
|
+
}
|
|
3865
3872
|
generateLlmsTxt(domain, data, options) {
|
|
3866
3873
|
const pages = this.generateAllMatrices(domain, data, options);
|
|
3867
3874
|
const lines = [
|
|
@@ -3876,6 +3883,91 @@ ${urls}
|
|
|
3876
3883
|
return lines.join(`
|
|
3877
3884
|
`);
|
|
3878
3885
|
}
|
|
3886
|
+
generateRobotsTxt(domain, options) {
|
|
3887
|
+
const cleanDomain = domain.replace(/\/+$/, "");
|
|
3888
|
+
const sitemap = options?.sitemapUrl || `${cleanDomain}/sitemap.xml`;
|
|
3889
|
+
const disallows = options?.disallowPaths || ["/api/", "/admin/", "/private/"];
|
|
3890
|
+
const lines = [
|
|
3891
|
+
"User-agent: *",
|
|
3892
|
+
"Allow: /",
|
|
3893
|
+
...disallows.map((d) => `Disallow: ${d}`),
|
|
3894
|
+
""
|
|
3895
|
+
];
|
|
3896
|
+
if (options?.allowAiBots !== false) {
|
|
3897
|
+
lines.push("# AI Search Crawlers Optimization (AEO/GEO)", "User-agent: GPTBot", "Allow: /", "", "User-agent: ClaudeBot", "Allow: /", "", "User-agent: PerplexityBot", "Allow: /", "", "User-agent: Applebot", "Allow: /", "");
|
|
3898
|
+
}
|
|
3899
|
+
lines.push(`Sitemap: ${sitemap}`);
|
|
3900
|
+
return lines.join(`
|
|
3901
|
+
`);
|
|
3902
|
+
}
|
|
3903
|
+
getTelemetryPayload(domain, data, options) {
|
|
3904
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3905
|
+
const indexedPages = pages.filter((p) => p.robots.includes("index"));
|
|
3906
|
+
const matrixBreakdown = {};
|
|
3907
|
+
for (const p of pages) {
|
|
3908
|
+
matrixBreakdown[p.matrixFamily] = (matrixBreakdown[p.matrixFamily] || 0) + 1;
|
|
3909
|
+
}
|
|
3910
|
+
return {
|
|
3911
|
+
domain,
|
|
3912
|
+
brandName: options.brandName,
|
|
3913
|
+
language: options.language || "en",
|
|
3914
|
+
languages: options.languages || [options.language || "en"],
|
|
3915
|
+
totalPages: pages.length,
|
|
3916
|
+
indexedPages: indexedPages.length,
|
|
3917
|
+
servicesCount: data.services?.length ?? 0,
|
|
3918
|
+
matrixBreakdown,
|
|
3919
|
+
timestamp: new Date().toISOString()
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
// src/i18n-detector.ts
|
|
3924
|
+
var SUPPORTED_CANONICAL_LOCALES = [
|
|
3925
|
+
"en",
|
|
3926
|
+
"fr",
|
|
3927
|
+
"es",
|
|
3928
|
+
"de",
|
|
3929
|
+
"it",
|
|
3930
|
+
"pt",
|
|
3931
|
+
"nl",
|
|
3932
|
+
"ru",
|
|
3933
|
+
"sv",
|
|
3934
|
+
"pl",
|
|
3935
|
+
"ja",
|
|
3936
|
+
"zh",
|
|
3937
|
+
"ar"
|
|
3938
|
+
];
|
|
3939
|
+
|
|
3940
|
+
class I18nDetector {
|
|
3941
|
+
static normalizeLocale(localeInput) {
|
|
3942
|
+
if (!localeInput || typeof localeInput !== "string")
|
|
3943
|
+
return "en";
|
|
3944
|
+
const clean = localeInput.toLowerCase().split(/[-_]/)[0].trim();
|
|
3945
|
+
return clean || "en";
|
|
3946
|
+
}
|
|
3947
|
+
static resolveActiveLocales(explicitLocales) {
|
|
3948
|
+
if (explicitLocales) {
|
|
3949
|
+
const list = Array.isArray(explicitLocales) ? explicitLocales : [explicitLocales];
|
|
3950
|
+
const normalized = list.map((l) => this.normalizeLocale(l)).filter(Boolean);
|
|
3951
|
+
return Array.from(new Set(normalized));
|
|
3952
|
+
}
|
|
3953
|
+
return ["en", "fr"];
|
|
3954
|
+
}
|
|
3955
|
+
static extractLocaleFromPath(pathname, activeLocales) {
|
|
3956
|
+
const cleanPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
3957
|
+
const segments = cleanPath.split("/").filter(Boolean);
|
|
3958
|
+
if (segments.length > 0 && activeLocales.includes(segments[0].toLowerCase())) {
|
|
3959
|
+
const locale = segments[0].toLowerCase();
|
|
3960
|
+
const remainingSegments = segments.slice(1);
|
|
3961
|
+
return {
|
|
3962
|
+
locale,
|
|
3963
|
+
remainingPath: `/${remainingSegments.join("/")}`
|
|
3964
|
+
};
|
|
3965
|
+
}
|
|
3966
|
+
return {
|
|
3967
|
+
locale: activeLocales[0] || "en",
|
|
3968
|
+
remainingPath: cleanPath
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3879
3971
|
}
|
|
3880
3972
|
// src/brand-icons.ts
|
|
3881
3973
|
var BRAND_ICONS = {
|
|
@@ -4342,13 +4434,14 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
4342
4434
|
|
|
4343
4435
|
export default function sitemap(): MetadataRoute.Sitemap {
|
|
4344
4436
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4437
|
+
return matrixEngine.generateAllMatrices(domain, PSEO_DATASET, SEO_CONFIG)
|
|
4438
|
+
.filter((p) => p.robots.includes("index"))
|
|
4439
|
+
.map((p) => ({
|
|
4440
|
+
url: p.canonicalUrl,
|
|
4441
|
+
lastModified: new Date(),
|
|
4442
|
+
changeFrequency: "weekly",
|
|
4443
|
+
priority: 0.8,
|
|
4444
|
+
}));
|
|
4352
4445
|
}
|
|
4353
4446
|
\`\`\`
|
|
4354
4447
|
|
|
@@ -4359,49 +4452,67 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
4359
4452
|
|
|
4360
4453
|
export async function GET() {
|
|
4361
4454
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4362
|
-
|
|
4363
|
-
const markdown =
|
|
4364
|
-
\`# \${SEO_CONFIG.brandName} Solutions Index\`,
|
|
4365
|
-
\`> Structured knowledge feed for LLMs and AI search engines (ChatGPT, Perplexity).\`,
|
|
4366
|
-
\`\`,
|
|
4367
|
-
\`## Solutions & Matrices\`,
|
|
4368
|
-
...pages.map((p) => \`- [\${p.h1}](\${p.canonicalUrl}): \${p.description}\`),
|
|
4369
|
-
].join("\\n");
|
|
4455
|
+
// โก 1-Line high-density Markdown feed for ChatGPT Search & Perplexity
|
|
4456
|
+
const markdown = matrixEngine.generateLlmsTxt(domain, PSEO_DATASET, SEO_CONFIG);
|
|
4370
4457
|
return new NextResponse(markdown, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
|
|
4371
4458
|
}
|
|
4372
4459
|
\`\`\`
|
|
4373
4460
|
|
|
4461
|
+
#### File 5: Dynamic AI Search & Bot Rules (\`app/robots.ts\` or \`public/robots.txt\`)
|
|
4462
|
+
\`\`\`typescript
|
|
4463
|
+
import { MetadataRoute } from "next";
|
|
4464
|
+
import { matrixEngine } from "@/lib/seo";
|
|
4465
|
+
|
|
4466
|
+
export default function robots(): MetadataRoute.Robots {
|
|
4467
|
+
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4468
|
+
return {
|
|
4469
|
+
rules: [
|
|
4470
|
+
{ userAgent: "*", allow: "/", disallow: ["/api/", "/admin/"] },
|
|
4471
|
+
{ userAgent: ["GPTBot", "ClaudeBot", "PerplexityBot", "Applebot"], allow: "/" },
|
|
4472
|
+
],
|
|
4473
|
+
sitemap: \`\${domain}/sitemap.xml\`,
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
4476
|
+
\`\`\`
|
|
4477
|
+
|
|
4374
4478
|
---
|
|
4375
4479
|
|
|
4376
|
-
### \
|
|
4480
|
+
### \uD83E\uDDF0 6. THE COMPLETE LYNXSEO STUDIO ENGINE & TOOL SUITE
|
|
4377
4481
|
|
|
4378
|
-
|
|
4379
|
-
- Comparisons: \`/vs/{competitor}\`
|
|
4380
|
-
- Alternatives: \`/alternatives/{competitor}\` (Zero keyword stuttering)
|
|
4381
|
-
- Pricing: \`/pricing/{competitor}\`
|
|
4382
|
-
- Audiences: \`/for/{target}\` (Unified industry/role mapping, anti-cannibalization)
|
|
4383
|
-
- Integrations: \`/integrations/{app}\` (Clean slug without stop words)
|
|
4384
|
-
- Use Cases: \`/use-cases/{useCase}\` (Actionable workflows with HowTo JSON-LD)
|
|
4385
|
-
- Templates: \`/templates/{slug}\` (High-converting spreadsheet/notion lead magnets)
|
|
4386
|
-
- Glossary: \`/glossary/{term}\` (Topic authority cluster hub)
|
|
4387
|
-
- Tools: \`/tools/{calculator}\` (Interactive ROI & value estimators)
|
|
4388
|
-
- Local Geo: \`/solutions/{service}/{country}/{city}\` (Tiered Indexing & Mesh Links)
|
|
4482
|
+
The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
4389
4483
|
|
|
4390
|
-
|
|
4391
|
-
-
|
|
4392
|
-
-
|
|
4393
|
-
-
|
|
4394
|
-
- **Ecosystem & Integrations (10):** Module ร App (e.g., CRM ร Shopify), Connector ร Webhook Trigger.
|
|
4395
|
-
- **Problem Playbooks (8):** Pain Point ร Step-by-Step Playbook, Bottleneck ร ROI.
|
|
4396
|
-
- **Interactive Calculators (6):** Time-Saved Estimator, Revenue Uplift Simulator.
|
|
4397
|
-
- **Topic Authority Clusters (6):** Financial Metrics (MRR, LTV), Technical Protocols (OAuth, Webhook).
|
|
4484
|
+
1. **โก In-Memory Programmatic Matrix Engine (\`matrixEngine\`):**
|
|
4485
|
+
- \`resolvePage(slug, domain, data, config)\`: Resolves full programmatic pages in < 0.05ms in local RAM.
|
|
4486
|
+
- \`resolveServicePage(serviceSlug, citySlug, ...)\`: Dedicated routing for \`app/[service]/[city]/page.tsx\`.
|
|
4487
|
+
- \`generateSitemapXml()\`, \`generateLlmsTxt()\`, \`generateRobotsTxt()\`.
|
|
4398
4488
|
|
|
4399
|
-
|
|
4489
|
+
2. **\uD83C\uDF0D Built-in Global Demographics (\`built-in-locations.ts\`):**
|
|
4490
|
+
- Automatically provisions verified cities, populations, GPS coordinates, and currencies across France, Spain, Germany, UK, US, Belgium, Switzerland, Italy, Canada, Europe, and International markets. Zero manual city typing.
|
|
4491
|
+
|
|
4492
|
+
3. **\uD83C\uDF10 Dynamic i18n Detector (\`I18nDetector\`):**
|
|
4493
|
+
- Seamless auto-detection and normalization across \`next-intl\`, \`i18next\`, \`paraglide\`, and \`astro:i18n\`. Adapts Google schemas and local currencies automatically.
|
|
4494
|
+
|
|
4495
|
+
4. **\uD83C\uDFA8 Vector Brand & Social Icons (\`renderBrandIconSvg\`):**
|
|
4496
|
+
- Zero-dependency official SVG vectors for 30+ brands (Facebook, Instagram, LinkedIn, Shopify, Slack, WhatsApp, Google, GitHub, TikTok, YouTube).
|
|
4497
|
+
|
|
4498
|
+
5. **\uD83C\uDFDB๏ธ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
4499
|
+
- \`buildAggregateRating\` (Google Gold Stars 4.9โ
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
4500
|
+
|
|
4501
|
+
6. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
4502
|
+
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
4503
|
+
|
|
4504
|
+
7. **โก SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
4505
|
+
- Combinatorial matrix generation: Products ร Modifiers ร Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
4506
|
+
|
|
4507
|
+
8. **โ๏ธ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
4508
|
+
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
4400
4509
|
|
|
4401
|
-
|
|
4510
|
+
9. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
4511
|
+
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
4402
4512
|
|
|
4403
|
-
|
|
4404
|
-
-
|
|
4513
|
+
10. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
|
|
4514
|
+
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
4515
|
+
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
4405
4516
|
`.trim();
|
|
4406
4517
|
function getSeoAgentPrompt(customContext) {
|
|
4407
4518
|
if (!customContext)
|
package/dist/index.mjs
CHANGED
|
@@ -3757,6 +3757,11 @@ class PseoMatrixEngine {
|
|
|
3757
3757
|
${urls}
|
|
3758
3758
|
</urlset>`;
|
|
3759
3759
|
}
|
|
3760
|
+
resolveServicePage(serviceSlug, citySlug, domain, data, options) {
|
|
3761
|
+
const cleanService = cleanSeoSlug(serviceSlug, { language: options.language });
|
|
3762
|
+
const cleanCity = cleanSeoSlug(citySlug, { language: options.language });
|
|
3763
|
+
return this.resolvePage([cleanService, cleanCity], domain, data, options);
|
|
3764
|
+
}
|
|
3760
3765
|
generateLlmsTxt(domain, data, options) {
|
|
3761
3766
|
const pages = this.generateAllMatrices(domain, data, options);
|
|
3762
3767
|
const lines = [
|
|
@@ -3771,6 +3776,91 @@ ${urls}
|
|
|
3771
3776
|
return lines.join(`
|
|
3772
3777
|
`);
|
|
3773
3778
|
}
|
|
3779
|
+
generateRobotsTxt(domain, options) {
|
|
3780
|
+
const cleanDomain = domain.replace(/\/+$/, "");
|
|
3781
|
+
const sitemap = options?.sitemapUrl || `${cleanDomain}/sitemap.xml`;
|
|
3782
|
+
const disallows = options?.disallowPaths || ["/api/", "/admin/", "/private/"];
|
|
3783
|
+
const lines = [
|
|
3784
|
+
"User-agent: *",
|
|
3785
|
+
"Allow: /",
|
|
3786
|
+
...disallows.map((d) => `Disallow: ${d}`),
|
|
3787
|
+
""
|
|
3788
|
+
];
|
|
3789
|
+
if (options?.allowAiBots !== false) {
|
|
3790
|
+
lines.push("# AI Search Crawlers Optimization (AEO/GEO)", "User-agent: GPTBot", "Allow: /", "", "User-agent: ClaudeBot", "Allow: /", "", "User-agent: PerplexityBot", "Allow: /", "", "User-agent: Applebot", "Allow: /", "");
|
|
3791
|
+
}
|
|
3792
|
+
lines.push(`Sitemap: ${sitemap}`);
|
|
3793
|
+
return lines.join(`
|
|
3794
|
+
`);
|
|
3795
|
+
}
|
|
3796
|
+
getTelemetryPayload(domain, data, options) {
|
|
3797
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3798
|
+
const indexedPages = pages.filter((p) => p.robots.includes("index"));
|
|
3799
|
+
const matrixBreakdown = {};
|
|
3800
|
+
for (const p of pages) {
|
|
3801
|
+
matrixBreakdown[p.matrixFamily] = (matrixBreakdown[p.matrixFamily] || 0) + 1;
|
|
3802
|
+
}
|
|
3803
|
+
return {
|
|
3804
|
+
domain,
|
|
3805
|
+
brandName: options.brandName,
|
|
3806
|
+
language: options.language || "en",
|
|
3807
|
+
languages: options.languages || [options.language || "en"],
|
|
3808
|
+
totalPages: pages.length,
|
|
3809
|
+
indexedPages: indexedPages.length,
|
|
3810
|
+
servicesCount: data.services?.length ?? 0,
|
|
3811
|
+
matrixBreakdown,
|
|
3812
|
+
timestamp: new Date().toISOString()
|
|
3813
|
+
};
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
// src/i18n-detector.ts
|
|
3817
|
+
var SUPPORTED_CANONICAL_LOCALES = [
|
|
3818
|
+
"en",
|
|
3819
|
+
"fr",
|
|
3820
|
+
"es",
|
|
3821
|
+
"de",
|
|
3822
|
+
"it",
|
|
3823
|
+
"pt",
|
|
3824
|
+
"nl",
|
|
3825
|
+
"ru",
|
|
3826
|
+
"sv",
|
|
3827
|
+
"pl",
|
|
3828
|
+
"ja",
|
|
3829
|
+
"zh",
|
|
3830
|
+
"ar"
|
|
3831
|
+
];
|
|
3832
|
+
|
|
3833
|
+
class I18nDetector {
|
|
3834
|
+
static normalizeLocale(localeInput) {
|
|
3835
|
+
if (!localeInput || typeof localeInput !== "string")
|
|
3836
|
+
return "en";
|
|
3837
|
+
const clean = localeInput.toLowerCase().split(/[-_]/)[0].trim();
|
|
3838
|
+
return clean || "en";
|
|
3839
|
+
}
|
|
3840
|
+
static resolveActiveLocales(explicitLocales) {
|
|
3841
|
+
if (explicitLocales) {
|
|
3842
|
+
const list = Array.isArray(explicitLocales) ? explicitLocales : [explicitLocales];
|
|
3843
|
+
const normalized = list.map((l) => this.normalizeLocale(l)).filter(Boolean);
|
|
3844
|
+
return Array.from(new Set(normalized));
|
|
3845
|
+
}
|
|
3846
|
+
return ["en", "fr"];
|
|
3847
|
+
}
|
|
3848
|
+
static extractLocaleFromPath(pathname, activeLocales) {
|
|
3849
|
+
const cleanPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
3850
|
+
const segments = cleanPath.split("/").filter(Boolean);
|
|
3851
|
+
if (segments.length > 0 && activeLocales.includes(segments[0].toLowerCase())) {
|
|
3852
|
+
const locale = segments[0].toLowerCase();
|
|
3853
|
+
const remainingSegments = segments.slice(1);
|
|
3854
|
+
return {
|
|
3855
|
+
locale,
|
|
3856
|
+
remainingPath: `/${remainingSegments.join("/")}`
|
|
3857
|
+
};
|
|
3858
|
+
}
|
|
3859
|
+
return {
|
|
3860
|
+
locale: activeLocales[0] || "en",
|
|
3861
|
+
remainingPath: cleanPath
|
|
3862
|
+
};
|
|
3863
|
+
}
|
|
3774
3864
|
}
|
|
3775
3865
|
// src/brand-icons.ts
|
|
3776
3866
|
var BRAND_ICONS = {
|
|
@@ -4237,13 +4327,14 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
4237
4327
|
|
|
4238
4328
|
export default function sitemap(): MetadataRoute.Sitemap {
|
|
4239
4329
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4330
|
+
return matrixEngine.generateAllMatrices(domain, PSEO_DATASET, SEO_CONFIG)
|
|
4331
|
+
.filter((p) => p.robots.includes("index"))
|
|
4332
|
+
.map((p) => ({
|
|
4333
|
+
url: p.canonicalUrl,
|
|
4334
|
+
lastModified: new Date(),
|
|
4335
|
+
changeFrequency: "weekly",
|
|
4336
|
+
priority: 0.8,
|
|
4337
|
+
}));
|
|
4247
4338
|
}
|
|
4248
4339
|
\`\`\`
|
|
4249
4340
|
|
|
@@ -4254,49 +4345,67 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
4254
4345
|
|
|
4255
4346
|
export async function GET() {
|
|
4256
4347
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4257
|
-
|
|
4258
|
-
const markdown =
|
|
4259
|
-
\`# \${SEO_CONFIG.brandName} Solutions Index\`,
|
|
4260
|
-
\`> Structured knowledge feed for LLMs and AI search engines (ChatGPT, Perplexity).\`,
|
|
4261
|
-
\`\`,
|
|
4262
|
-
\`## Solutions & Matrices\`,
|
|
4263
|
-
...pages.map((p) => \`- [\${p.h1}](\${p.canonicalUrl}): \${p.description}\`),
|
|
4264
|
-
].join("\\n");
|
|
4348
|
+
// โก 1-Line high-density Markdown feed for ChatGPT Search & Perplexity
|
|
4349
|
+
const markdown = matrixEngine.generateLlmsTxt(domain, PSEO_DATASET, SEO_CONFIG);
|
|
4265
4350
|
return new NextResponse(markdown, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
|
|
4266
4351
|
}
|
|
4267
4352
|
\`\`\`
|
|
4268
4353
|
|
|
4354
|
+
#### File 5: Dynamic AI Search & Bot Rules (\`app/robots.ts\` or \`public/robots.txt\`)
|
|
4355
|
+
\`\`\`typescript
|
|
4356
|
+
import { MetadataRoute } from "next";
|
|
4357
|
+
import { matrixEngine } from "@/lib/seo";
|
|
4358
|
+
|
|
4359
|
+
export default function robots(): MetadataRoute.Robots {
|
|
4360
|
+
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4361
|
+
return {
|
|
4362
|
+
rules: [
|
|
4363
|
+
{ userAgent: "*", allow: "/", disallow: ["/api/", "/admin/"] },
|
|
4364
|
+
{ userAgent: ["GPTBot", "ClaudeBot", "PerplexityBot", "Applebot"], allow: "/" },
|
|
4365
|
+
],
|
|
4366
|
+
sitemap: \`\${domain}/sitemap.xml\`,
|
|
4367
|
+
};
|
|
4368
|
+
}
|
|
4369
|
+
\`\`\`
|
|
4370
|
+
|
|
4269
4371
|
---
|
|
4270
4372
|
|
|
4271
|
-
### \
|
|
4373
|
+
### \uD83E\uDDF0 6. THE COMPLETE LYNXSEO STUDIO ENGINE & TOOL SUITE
|
|
4272
4374
|
|
|
4273
|
-
|
|
4274
|
-
- Comparisons: \`/vs/{competitor}\`
|
|
4275
|
-
- Alternatives: \`/alternatives/{competitor}\` (Zero keyword stuttering)
|
|
4276
|
-
- Pricing: \`/pricing/{competitor}\`
|
|
4277
|
-
- Audiences: \`/for/{target}\` (Unified industry/role mapping, anti-cannibalization)
|
|
4278
|
-
- Integrations: \`/integrations/{app}\` (Clean slug without stop words)
|
|
4279
|
-
- Use Cases: \`/use-cases/{useCase}\` (Actionable workflows with HowTo JSON-LD)
|
|
4280
|
-
- Templates: \`/templates/{slug}\` (High-converting spreadsheet/notion lead magnets)
|
|
4281
|
-
- Glossary: \`/glossary/{term}\` (Topic authority cluster hub)
|
|
4282
|
-
- Tools: \`/tools/{calculator}\` (Interactive ROI & value estimators)
|
|
4283
|
-
- Local Geo: \`/solutions/{service}/{country}/{city}\` (Tiered Indexing & Mesh Links)
|
|
4375
|
+
The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
4284
4376
|
|
|
4285
|
-
|
|
4286
|
-
-
|
|
4287
|
-
-
|
|
4288
|
-
-
|
|
4289
|
-
- **Ecosystem & Integrations (10):** Module ร App (e.g., CRM ร Shopify), Connector ร Webhook Trigger.
|
|
4290
|
-
- **Problem Playbooks (8):** Pain Point ร Step-by-Step Playbook, Bottleneck ร ROI.
|
|
4291
|
-
- **Interactive Calculators (6):** Time-Saved Estimator, Revenue Uplift Simulator.
|
|
4292
|
-
- **Topic Authority Clusters (6):** Financial Metrics (MRR, LTV), Technical Protocols (OAuth, Webhook).
|
|
4377
|
+
1. **โก In-Memory Programmatic Matrix Engine (\`matrixEngine\`):**
|
|
4378
|
+
- \`resolvePage(slug, domain, data, config)\`: Resolves full programmatic pages in < 0.05ms in local RAM.
|
|
4379
|
+
- \`resolveServicePage(serviceSlug, citySlug, ...)\`: Dedicated routing for \`app/[service]/[city]/page.tsx\`.
|
|
4380
|
+
- \`generateSitemapXml()\`, \`generateLlmsTxt()\`, \`generateRobotsTxt()\`.
|
|
4293
4381
|
|
|
4294
|
-
|
|
4382
|
+
2. **\uD83C\uDF0D Built-in Global Demographics (\`built-in-locations.ts\`):**
|
|
4383
|
+
- Automatically provisions verified cities, populations, GPS coordinates, and currencies across France, Spain, Germany, UK, US, Belgium, Switzerland, Italy, Canada, Europe, and International markets. Zero manual city typing.
|
|
4384
|
+
|
|
4385
|
+
3. **\uD83C\uDF10 Dynamic i18n Detector (\`I18nDetector\`):**
|
|
4386
|
+
- Seamless auto-detection and normalization across \`next-intl\`, \`i18next\`, \`paraglide\`, and \`astro:i18n\`. Adapts Google schemas and local currencies automatically.
|
|
4387
|
+
|
|
4388
|
+
4. **\uD83C\uDFA8 Vector Brand & Social Icons (\`renderBrandIconSvg\`):**
|
|
4389
|
+
- Zero-dependency official SVG vectors for 30+ brands (Facebook, Instagram, LinkedIn, Shopify, Slack, WhatsApp, Google, GitHub, TikTok, YouTube).
|
|
4390
|
+
|
|
4391
|
+
5. **\uD83C\uDFDB๏ธ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
4392
|
+
- \`buildAggregateRating\` (Google Gold Stars 4.9โ
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
4393
|
+
|
|
4394
|
+
6. **\uD83D\uDD0D URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
4395
|
+
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
4396
|
+
|
|
4397
|
+
7. **โก SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
4398
|
+
- Combinatorial matrix generation: Products ร Modifiers ร Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
4399
|
+
|
|
4400
|
+
8. **โ๏ธ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
4401
|
+
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
4295
4402
|
|
|
4296
|
-
|
|
4403
|
+
9. **\uD83D\uDCCA Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
4404
|
+
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
4297
4405
|
|
|
4298
|
-
|
|
4299
|
-
-
|
|
4406
|
+
10. **\uD83E\uDDF9 URL Slug Engine & Schema.org Graphs:**
|
|
4407
|
+
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
4408
|
+
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
4300
4409
|
`.trim();
|
|
4301
4410
|
function getSeoAgentPrompt(customContext) {
|
|
4302
4411
|
if (!customContext)
|
|
@@ -6464,6 +6573,7 @@ export {
|
|
|
6464
6573
|
SerpClient,
|
|
6465
6574
|
SeoOpportunitiesDecayDetector,
|
|
6466
6575
|
SchemaGraphBuilder,
|
|
6576
|
+
SUPPORTED_CANONICAL_LOCALES,
|
|
6467
6577
|
SCHEMA_LOCAL_BUSINESS_MAP,
|
|
6468
6578
|
RssSyndicationFeedGenerator,
|
|
6469
6579
|
RealReviewsSyncEngine,
|
|
@@ -6487,6 +6597,7 @@ export {
|
|
|
6487
6597
|
IsrCacheManager,
|
|
6488
6598
|
InstantMatrixSearchEngine,
|
|
6489
6599
|
IndexNowClient,
|
|
6600
|
+
I18nDetector,
|
|
6490
6601
|
HyperswitchGateway,
|
|
6491
6602
|
GeoMeshLinkingEngine,
|
|
6492
6603
|
ExtendedSchemaGraphBuilder,
|
package/dist/matrix-engine.d.ts
CHANGED
|
@@ -221,8 +221,35 @@ export declare class PseoMatrixEngine {
|
|
|
221
221
|
* Generates a fully formatted XML Sitemap string.
|
|
222
222
|
*/
|
|
223
223
|
generateSitemapXml(domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): string;
|
|
224
|
+
/**
|
|
225
|
+
* Resolves a page for a specific module/service and city.
|
|
226
|
+
* Useful when organizing code as app/[service]/[city]/page.tsx
|
|
227
|
+
*/
|
|
228
|
+
resolveServicePage(serviceSlug: string, citySlug: string, domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): GeneratedPageMeta | undefined;
|
|
224
229
|
/**
|
|
225
230
|
* Generates an official /llms.txt Markdown directory for AI search bots.
|
|
226
231
|
*/
|
|
227
232
|
generateLlmsTxt(domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): string;
|
|
233
|
+
/**
|
|
234
|
+
* Generates a modern robots.txt allowing search engines and AI agents with sitemap link.
|
|
235
|
+
*/
|
|
236
|
+
generateRobotsTxt(domain: string, options?: {
|
|
237
|
+
sitemapUrl?: string;
|
|
238
|
+
allowAiBots?: boolean;
|
|
239
|
+
disallowPaths?: string[];
|
|
240
|
+
}): string;
|
|
241
|
+
/**
|
|
242
|
+
* Computes telemetry & page metering data for syncing with LynxSEO Studio dashboard.
|
|
243
|
+
*/
|
|
244
|
+
getTelemetryPayload(domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): {
|
|
245
|
+
domain: string;
|
|
246
|
+
brandName: string;
|
|
247
|
+
language: string;
|
|
248
|
+
languages: string[];
|
|
249
|
+
totalPages: number;
|
|
250
|
+
indexedPages: number;
|
|
251
|
+
servicesCount: number;
|
|
252
|
+
matrixBreakdown: Record<string, number>;
|
|
253
|
+
timestamp: string;
|
|
254
|
+
};
|
|
228
255
|
}
|
package/package.json
CHANGED
package/src/engine.test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { getSeoAgentPrompt } from "./llm-prompt";
|
|
|
7
7
|
import { UrlyticsEngine } from "./urlytics-engine";
|
|
8
8
|
import { KeywordPermutatorEngine } from "./keyword-permutator";
|
|
9
9
|
import { renderBrandIconSvg } from "./brand-icons";
|
|
10
|
+
import { I18nDetector } from "./i18n-detector";
|
|
10
11
|
|
|
11
12
|
describe("Multilingual SEO Slug Engine (10+ Languages)", () => {
|
|
12
13
|
it("English: Strips stop words and years", () => {
|
|
@@ -234,4 +235,34 @@ describe("Audited Reference Engines (Advertools, Santifer, Seonaut)", () => {
|
|
|
234
235
|
expect(paths).toContain("/autopost-facebook/madrid");
|
|
235
236
|
expect(paths).toContain("/autopost-facebook/barcelona");
|
|
236
237
|
});
|
|
238
|
+
|
|
239
|
+
it("I18nDetector: Normalizes locales and extracts locale from pathname", () => {
|
|
240
|
+
expect(I18nDetector.normalizeLocale("fr-FR")).toBe("fr");
|
|
241
|
+
expect(I18nDetector.normalizeLocale("en_US")).toBe("en");
|
|
242
|
+
|
|
243
|
+
const extraction = I18nDetector.extractLocaleFromPath("/fr/autopost-facebook/paris", ["fr", "en", "es"]);
|
|
244
|
+
expect(extraction.locale).toBe("fr");
|
|
245
|
+
expect(extraction.remainingPath).toBe("/autopost-facebook/paris");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("PseoMatrixEngine: resolveServicePage, generateRobotsTxt, and getTelemetryPayload", () => {
|
|
249
|
+
const engine = new PseoMatrixEngine();
|
|
250
|
+
const data = {
|
|
251
|
+
services: [{ slug: "crm", name: "CRM", category: "Sales" }],
|
|
252
|
+
locations: [{ slug: "paris", name: "Paris", country: "France" }],
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const servicePage = engine.resolveServicePage("crm", "paris", "https://acme.com", data, { brandName: "Acme" });
|
|
256
|
+
expect(servicePage).toBeDefined();
|
|
257
|
+
expect(servicePage?.h1).toContain("CRM");
|
|
258
|
+
|
|
259
|
+
const robots = engine.generateRobotsTxt("https://acme.com", { allowAiBots: true });
|
|
260
|
+
expect(robots).toContain("User-agent: GPTBot");
|
|
261
|
+
expect(robots).toContain("Sitemap: https://acme.com/sitemap.xml");
|
|
262
|
+
|
|
263
|
+
const telemetry = engine.getTelemetryPayload("https://acme.com", data, { brandName: "Acme" });
|
|
264
|
+
expect(telemetry.totalPages).toBeGreaterThan(0);
|
|
265
|
+
expect(telemetry.brandName).toBe("Acme");
|
|
266
|
+
expect(telemetry.servicesCount).toBe(1);
|
|
267
|
+
});
|
|
237
268
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ๐ Dynamic i18n & Locale Auto-Detector
|
|
3
|
+
* Automatically detects and synchronizes website locales without requiring hardcoded lists.
|
|
4
|
+
* Compatible with next-intl, next-i18next, i18next, Paraglide, and Astro i18n.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const SUPPORTED_CANONICAL_LOCALES = [
|
|
8
|
+
"en",
|
|
9
|
+
"fr",
|
|
10
|
+
"es",
|
|
11
|
+
"de",
|
|
12
|
+
"it",
|
|
13
|
+
"pt",
|
|
14
|
+
"nl",
|
|
15
|
+
"ru",
|
|
16
|
+
"sv",
|
|
17
|
+
"pl",
|
|
18
|
+
"ja",
|
|
19
|
+
"zh",
|
|
20
|
+
"ar",
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
export type SupportedLocale = (typeof SUPPORTED_CANONICAL_LOCALES)[number];
|
|
24
|
+
|
|
25
|
+
export class I18nDetector {
|
|
26
|
+
/**
|
|
27
|
+
* Resolves a clean 2-letter ISO language code from any locale string (e.g. "fr-FR" -> "fr").
|
|
28
|
+
*/
|
|
29
|
+
static normalizeLocale(localeInput?: string): string {
|
|
30
|
+
if (!localeInput || typeof localeInput !== "string") return "en";
|
|
31
|
+
const clean = localeInput.toLowerCase().split(/[-_]/)[0].trim();
|
|
32
|
+
return clean || "en";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Auto-detects and extracts active locales from common environment variables or array inputs.
|
|
37
|
+
*/
|
|
38
|
+
static resolveActiveLocales(explicitLocales?: string[] | string): string[] {
|
|
39
|
+
if (explicitLocales) {
|
|
40
|
+
const list = Array.isArray(explicitLocales) ? explicitLocales : [explicitLocales];
|
|
41
|
+
const normalized = list.map((l) => this.normalizeLocale(l)).filter(Boolean);
|
|
42
|
+
return Array.from(new Set(normalized));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Default fallback
|
|
46
|
+
return ["en", "fr"];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Matches whether a given path segment is a language prefix (e.g. "/fr/autopost-facebook/paris").
|
|
51
|
+
*/
|
|
52
|
+
static extractLocaleFromPath(pathname: string, activeLocales: string[]): { locale: string; remainingPath: string } {
|
|
53
|
+
const cleanPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
54
|
+
const segments = cleanPath.split("/").filter(Boolean);
|
|
55
|
+
|
|
56
|
+
if (segments.length > 0 && activeLocales.includes(segments[0].toLowerCase())) {
|
|
57
|
+
const locale = segments[0].toLowerCase();
|
|
58
|
+
const remainingSegments = segments.slice(1);
|
|
59
|
+
return {
|
|
60
|
+
locale,
|
|
61
|
+
remainingPath: `/${remainingSegments.join("/")}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
locale: activeLocales[0] || "en",
|
|
67
|
+
remainingPath: cleanPath,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from "./slug-engine";
|
|
|
15
15
|
export * from "./legal-disclaimers";
|
|
16
16
|
export * from "./matrix-engine";
|
|
17
17
|
export * from "./built-in-locations";
|
|
18
|
+
export * from "./i18n-detector";
|
|
18
19
|
export * from "./brand-icons";
|
|
19
20
|
export * from "./urlytics-engine";
|
|
20
21
|
export * from "./keyword-permutator";
|
package/src/llm-prompt.ts
CHANGED
|
@@ -214,13 +214,14 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
214
214
|
|
|
215
215
|
export default function sitemap(): MetadataRoute.Sitemap {
|
|
216
216
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
217
|
+
return matrixEngine.generateAllMatrices(domain, PSEO_DATASET, SEO_CONFIG)
|
|
218
|
+
.filter((p) => p.robots.includes("index"))
|
|
219
|
+
.map((p) => ({
|
|
220
|
+
url: p.canonicalUrl,
|
|
221
|
+
lastModified: new Date(),
|
|
222
|
+
changeFrequency: "weekly",
|
|
223
|
+
priority: 0.8,
|
|
224
|
+
}));
|
|
224
225
|
}
|
|
225
226
|
\`\`\`
|
|
226
227
|
|
|
@@ -231,49 +232,67 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
231
232
|
|
|
232
233
|
export async function GET() {
|
|
233
234
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
234
|
-
|
|
235
|
-
const markdown =
|
|
236
|
-
\`# \${SEO_CONFIG.brandName} Solutions Index\`,
|
|
237
|
-
\`> Structured knowledge feed for LLMs and AI search engines (ChatGPT, Perplexity).\`,
|
|
238
|
-
\`\`,
|
|
239
|
-
\`## Solutions & Matrices\`,
|
|
240
|
-
...pages.map((p) => \`- [\${p.h1}](\${p.canonicalUrl}): \${p.description}\`),
|
|
241
|
-
].join("\\n");
|
|
235
|
+
// โก 1-Line high-density Markdown feed for ChatGPT Search & Perplexity
|
|
236
|
+
const markdown = matrixEngine.generateLlmsTxt(domain, PSEO_DATASET, SEO_CONFIG);
|
|
242
237
|
return new NextResponse(markdown, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
|
|
243
238
|
}
|
|
244
239
|
\`\`\`
|
|
245
240
|
|
|
246
|
-
|
|
241
|
+
#### File 5: Dynamic AI Search & Bot Rules (\`app/robots.ts\` or \`public/robots.txt\`)
|
|
242
|
+
\`\`\`typescript
|
|
243
|
+
import { MetadataRoute } from "next";
|
|
244
|
+
import { matrixEngine } from "@/lib/seo";
|
|
247
245
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
- Tools: \`/tools/{calculator}\` (Interactive ROI & value estimators)
|
|
260
|
-
- Local Geo: \`/solutions/{service}/{country}/{city}\` (Tiered Indexing & Mesh Links)
|
|
261
|
-
|
|
262
|
-
2. **50+ Specialized Sub-Matrix Dimensions:**
|
|
263
|
-
- **Industry & Regulatory (12):** Sector ร Compliance (e.g., GDPR Law Firm), Sector ร Team Size.
|
|
264
|
-
- **Role & Workflow (10):** Role ร Core KPI (e.g., Sales Director Revenue), Role ร Daily Toolchain.
|
|
265
|
-
- **Multi-Format Templates (8):** Subject ร Format (Excel .xlsx, Notion, Google Sheets, Word, PDF).
|
|
266
|
-
- **Ecosystem & Integrations (10):** Module ร App (e.g., CRM ร Shopify), Connector ร Webhook Trigger.
|
|
267
|
-
- **Problem Playbooks (8):** Pain Point ร Step-by-Step Playbook, Bottleneck ร ROI.
|
|
268
|
-
- **Interactive Calculators (6):** Time-Saved Estimator, Revenue Uplift Simulator.
|
|
269
|
-
- **Topic Authority Clusters (6):** Financial Metrics (MRR, LTV), Technical Protocols (OAuth, Webhook).
|
|
246
|
+
export default function robots(): MetadataRoute.Robots {
|
|
247
|
+
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
248
|
+
return {
|
|
249
|
+
rules: [
|
|
250
|
+
{ userAgent: "*", allow: "/", disallow: ["/api/", "/admin/"] },
|
|
251
|
+
{ userAgent: ["GPTBot", "ClaudeBot", "PerplexityBot", "Applebot"], allow: "/" },
|
|
252
|
+
],
|
|
253
|
+
sitemap: \`\${domain}/sitemap.xml\`,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
\`\`\`
|
|
270
257
|
|
|
271
258
|
---
|
|
272
259
|
|
|
273
|
-
###
|
|
260
|
+
### ๐งฐ 6. THE COMPLETE LYNXSEO STUDIO ENGINE & TOOL SUITE
|
|
261
|
+
|
|
262
|
+
The SDK equips applications with 9 enterprise-grade SEO engines:
|
|
263
|
+
|
|
264
|
+
1. **โก In-Memory Programmatic Matrix Engine (\`matrixEngine\`):**
|
|
265
|
+
- \`resolvePage(slug, domain, data, config)\`: Resolves full programmatic pages in < 0.05ms in local RAM.
|
|
266
|
+
- \`resolveServicePage(serviceSlug, citySlug, ...)\`: Dedicated routing for \`app/[service]/[city]/page.tsx\`.
|
|
267
|
+
- \`generateSitemapXml()\`, \`generateLlmsTxt()\`, \`generateRobotsTxt()\`.
|
|
268
|
+
|
|
269
|
+
2. **๐ Built-in Global Demographics (\`built-in-locations.ts\`):**
|
|
270
|
+
- Automatically provisions verified cities, populations, GPS coordinates, and currencies across France, Spain, Germany, UK, US, Belgium, Switzerland, Italy, Canada, Europe, and International markets. Zero manual city typing.
|
|
271
|
+
|
|
272
|
+
3. **๐ Dynamic i18n Detector (\`I18nDetector\`):**
|
|
273
|
+
- Seamless auto-detection and normalization across \`next-intl\`, \`i18next\`, \`paraglide\`, and \`astro:i18n\`. Adapts Google schemas and local currencies automatically.
|
|
274
|
+
|
|
275
|
+
4. **๐จ Vector Brand & Social Icons (\`renderBrandIconSvg\`):**
|
|
276
|
+
- Zero-dependency official SVG vectors for 30+ brands (Facebook, Instagram, LinkedIn, Shopify, Slack, WhatsApp, Google, GitHub, TikTok, YouTube).
|
|
277
|
+
|
|
278
|
+
5. **๐๏ธ Google Schema.org Rich Graphs (\`ExtendedSchemaGraphBuilder\`):**
|
|
279
|
+
- \`buildAggregateRating\` (Google Gold Stars 4.9โ
), \`buildAggregateOffer\` (price ranges), \`buildLocalBusiness\` (GPS & opening hours), \`buildSoftwareApplication\`, \`buildHowTo\`, \`buildFAQPage\`, \`buildBreadcrumbs\`.
|
|
280
|
+
|
|
281
|
+
6. **๐ URL Decomposition & Analysis (\`UrlyticsEngine\`):**
|
|
282
|
+
- Deep structural directory decomposition, depth tracking, query parameter analysis, and slug tokenization (inspired by advertools).
|
|
283
|
+
|
|
284
|
+
7. **โก SEM Keyword Combinator (\`KeywordPermutatorEngine\`):**
|
|
285
|
+
- Combinatorial matrix generation: Products ร Modifiers ร Locations with match types (\`[exact]\`, \`"phrase"\`, \`+broad\`) and intent classification.
|
|
286
|
+
|
|
287
|
+
8. **โ๏ธ Legal & Editorial Compliance (\`LegalDisclaimerEngine\`):**
|
|
288
|
+
- 7 SeedRank-grade disclaimer templates, 90-day staleness verification, and multi-language anti-disparagement guardian.
|
|
289
|
+
|
|
290
|
+
9. **๐ Telemetry & Cloud Metering (\`matrixEngine.getTelemetryPayload\` & \`LynxAnalyticsClient\`):**
|
|
291
|
+
- Synchronizes total programmatic pages, indexed hubs, and AI bot crawl hits (GPTBot, ClaudeBot, PerplexityBot) with the LynxSEO Studio dashboard.
|
|
274
292
|
|
|
275
|
-
|
|
276
|
-
-
|
|
293
|
+
10. **๐งน URL Slug Engine & Schema.org Graphs:**
|
|
294
|
+
- \`cleanSeoSlug(text, { language })\`: Strips accents, stop words across 10+ languages, and non-alphanumeric noise.
|
|
295
|
+
- Outputs Google-validated Schema.org JSON-LD graphs with 0 syntax errors.
|
|
277
296
|
`.trim();
|
|
278
297
|
|
|
279
298
|
/**
|
package/src/matrix-engine.ts
CHANGED
|
@@ -883,6 +883,22 @@ ${urls}
|
|
|
883
883
|
</urlset>`;
|
|
884
884
|
}
|
|
885
885
|
|
|
886
|
+
/**
|
|
887
|
+
* Resolves a page for a specific module/service and city.
|
|
888
|
+
* Useful when organizing code as app/[service]/[city]/page.tsx
|
|
889
|
+
*/
|
|
890
|
+
resolveServicePage(
|
|
891
|
+
serviceSlug: string,
|
|
892
|
+
citySlug: string,
|
|
893
|
+
domain: string,
|
|
894
|
+
data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1],
|
|
895
|
+
options: MatrixOptions,
|
|
896
|
+
): GeneratedPageMeta | undefined {
|
|
897
|
+
const cleanService = cleanSeoSlug(serviceSlug, { language: options.language });
|
|
898
|
+
const cleanCity = cleanSeoSlug(citySlug, { language: options.language });
|
|
899
|
+
return this.resolvePage([cleanService, cleanCity], domain, data, options);
|
|
900
|
+
}
|
|
901
|
+
|
|
886
902
|
/**
|
|
887
903
|
* Generates an official /llms.txt Markdown directory for AI search bots.
|
|
888
904
|
*/
|
|
@@ -905,4 +921,73 @@ ${urls}
|
|
|
905
921
|
|
|
906
922
|
return lines.join("\n");
|
|
907
923
|
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Generates a modern robots.txt allowing search engines and AI agents with sitemap link.
|
|
927
|
+
*/
|
|
928
|
+
generateRobotsTxt(
|
|
929
|
+
domain: string,
|
|
930
|
+
options?: { sitemapUrl?: string; allowAiBots?: boolean; disallowPaths?: string[] },
|
|
931
|
+
): string {
|
|
932
|
+
const cleanDomain = domain.replace(/\/+$/, "");
|
|
933
|
+
const sitemap = options?.sitemapUrl || `${cleanDomain}/sitemap.xml`;
|
|
934
|
+
const disallows = options?.disallowPaths || ["/api/", "/admin/", "/private/"];
|
|
935
|
+
|
|
936
|
+
const lines: string[] = [
|
|
937
|
+
"User-agent: *",
|
|
938
|
+
"Allow: /",
|
|
939
|
+
...disallows.map((d) => `Disallow: ${d}`),
|
|
940
|
+
"",
|
|
941
|
+
];
|
|
942
|
+
|
|
943
|
+
if (options?.allowAiBots !== false) {
|
|
944
|
+
lines.push(
|
|
945
|
+
"# AI Search Crawlers Optimization (AEO/GEO)",
|
|
946
|
+
"User-agent: GPTBot",
|
|
947
|
+
"Allow: /",
|
|
948
|
+
"",
|
|
949
|
+
"User-agent: ClaudeBot",
|
|
950
|
+
"Allow: /",
|
|
951
|
+
"",
|
|
952
|
+
"User-agent: PerplexityBot",
|
|
953
|
+
"Allow: /",
|
|
954
|
+
"",
|
|
955
|
+
"User-agent: Applebot",
|
|
956
|
+
"Allow: /",
|
|
957
|
+
"",
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
lines.push(`Sitemap: ${sitemap}`);
|
|
962
|
+
return lines.join("\n");
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Computes telemetry & page metering data for syncing with LynxSEO Studio dashboard.
|
|
967
|
+
*/
|
|
968
|
+
getTelemetryPayload(
|
|
969
|
+
domain: string,
|
|
970
|
+
data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1],
|
|
971
|
+
options: MatrixOptions,
|
|
972
|
+
) {
|
|
973
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
974
|
+
const indexedPages = pages.filter((p) => p.robots.includes("index"));
|
|
975
|
+
|
|
976
|
+
const matrixBreakdown: Record<string, number> = {};
|
|
977
|
+
for (const p of pages) {
|
|
978
|
+
matrixBreakdown[p.matrixFamily] = (matrixBreakdown[p.matrixFamily] || 0) + 1;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return {
|
|
982
|
+
domain,
|
|
983
|
+
brandName: options.brandName,
|
|
984
|
+
language: options.language || "en",
|
|
985
|
+
languages: options.languages || [options.language || "en"],
|
|
986
|
+
totalPages: pages.length,
|
|
987
|
+
indexedPages: indexedPages.length,
|
|
988
|
+
servicesCount: data.services?.length ?? 0,
|
|
989
|
+
matrixBreakdown,
|
|
990
|
+
timestamp: new Date().toISOString(),
|
|
991
|
+
};
|
|
992
|
+
}
|
|
908
993
|
}
|