@lynxflow/seo-engine 1.5.6 → 1.5.7
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 +66 -17
- package/dist/index.mjs +66 -17
- package/dist/matrix-engine.d.ts +24 -0
- package/package.json +1 -1
- package/src/engine.test.ts +31 -0
- package/src/llm-prompt.ts +31 -16
- package/src/matrix-engine.ts +84 -1
package/dist/index.js
CHANGED
|
@@ -3272,7 +3272,7 @@ class PseoMatrixEngine {
|
|
|
3272
3272
|
const countryCode = cleanSeoSlug(loc.country, { language: lang });
|
|
3273
3273
|
const citySlug = cleanSeoSlug(loc.slug, { language: lang });
|
|
3274
3274
|
const serviceSlug = cleanSeoSlug(s.slug, { language: lang });
|
|
3275
|
-
const urlPath = `${prefix}/${serviceSlug}/${countryCode}/${citySlug}`;
|
|
3275
|
+
const urlPath = options.cleanDirectRoutes !== false ? `/${serviceSlug}/${citySlug}` : `${prefix}/${serviceSlug}/${countryCode}/${citySlug}`;
|
|
3276
3276
|
const fullUrl = `${cleanDomain}${urlPath}`;
|
|
3277
3277
|
const isIndexed = (loc.population ?? 20000) >= minPop;
|
|
3278
3278
|
const robots = isIndexed ? "index, follow" : "noindex, follow";
|
|
@@ -3695,6 +3695,40 @@ class PseoMatrixEngine {
|
|
|
3695
3695
|
}
|
|
3696
3696
|
return allPages;
|
|
3697
3697
|
}
|
|
3698
|
+
resolvePage(slugOrPath, domain, data, options) {
|
|
3699
|
+
const path = typeof slugOrPath === "string" ? slugOrPath.startsWith("/") ? slugOrPath : `/${slugOrPath}` : `/${slugOrPath.join("/")}`;
|
|
3700
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3701
|
+
return pages.find((p) => p.urlPath === path);
|
|
3702
|
+
}
|
|
3703
|
+
generateSitemapXml(domain, data, options) {
|
|
3704
|
+
const pages = this.generateAllMatrices(domain, data, options).filter((p) => p.robots.includes("index"));
|
|
3705
|
+
const now = new Date().toISOString();
|
|
3706
|
+
const urls = pages.map((p) => ` <url>
|
|
3707
|
+
<loc>${p.canonicalUrl}</loc>
|
|
3708
|
+
<lastmod>${now}</lastmod>
|
|
3709
|
+
<changefreq>weekly</changefreq>
|
|
3710
|
+
<priority>0.8</priority>
|
|
3711
|
+
</url>`).join(`
|
|
3712
|
+
`);
|
|
3713
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3714
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3715
|
+
${urls}
|
|
3716
|
+
</urlset>`;
|
|
3717
|
+
}
|
|
3718
|
+
generateLlmsTxt(domain, data, options) {
|
|
3719
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3720
|
+
const lines = [
|
|
3721
|
+
`# ${options.brandName} — AI Knowledge Graph & Page Hub`,
|
|
3722
|
+
`> Complete index of services, tools, integrations, and local solution hubs.`,
|
|
3723
|
+
"",
|
|
3724
|
+
`## Indexed Programmatic Hubs (${pages.length} Pages)`
|
|
3725
|
+
];
|
|
3726
|
+
for (const p of pages) {
|
|
3727
|
+
lines.push(`- [${p.h1}](${p.canonicalUrl}): ${p.description}`);
|
|
3728
|
+
}
|
|
3729
|
+
return lines.join(`
|
|
3730
|
+
`);
|
|
3731
|
+
}
|
|
3698
3732
|
}
|
|
3699
3733
|
// src/brand-icons.ts
|
|
3700
3734
|
var BRAND_ICONS = {
|
|
@@ -3984,7 +4018,21 @@ When discovering product modules, features, or services to build the SEO matrice
|
|
|
3984
4018
|
|
|
3985
4019
|
---
|
|
3986
4020
|
|
|
3987
|
-
### \
|
|
4021
|
+
### \uD83D\uDCCF 3. THE GOLDEN RULES OF URL ARCHITECTURE (MAX 3-4 SEGMENTS, ZERO PARASITE WORDS)
|
|
4022
|
+
|
|
4023
|
+
- **Rule A (2 to 3 URL Segments Ideal, 4 Maximum):**
|
|
4024
|
+
- ✅ **2 Segments (Top SEO Performance):** \`site.com/{service}/{city}\` (e.g. \`/autopost-facebook/lyon\`, \`/crm/paris\`).
|
|
4025
|
+
- ✅ **3 Segments (B2B Persona/Hub):** \`site.com/for/{target}/{city}\` or \`site.com/{locale}/{service}/{city}\`.
|
|
4026
|
+
- ❌ **Never 5 to 6 Segments:** Avoid \`/solutions/ai/autopost/facebook/fr/lyon\`.
|
|
4027
|
+
- **Rule B (Eliminate All Parasite Noise Words):**
|
|
4028
|
+
- Banish generic wrapper words like \`/solutions/\`, \`/pages/\`, \`/items/\`. Go direct to user search intent: What you do + Platform + Location.
|
|
4029
|
+
- **Rule C (The SDK Does 100% of the Heavy Lifting):**
|
|
4030
|
+
- The developer/AI only registers 3-4 product features and target cities in \`lib/seo.ts\`.
|
|
4031
|
+
- The SDK automatically resolves routes in memory via \`matrixEngine.resolvePage(params.slug)\`, generates complete Schema.org graphs (LocalBusiness, AggregateRating, AggregateOffer), creates AEO summaries, builds FAQ accordions, and manages mesh linking in < 0.05ms.
|
|
4032
|
+
|
|
4033
|
+
---
|
|
4034
|
+
|
|
4035
|
+
### \uD83C\uDFC6 4. THE ARCHITECTURAL PLAYBOOK OF SAAS TITANS (7M+ PAGES WITH 0 DB BOTTLENECKS)
|
|
3988
4036
|
|
|
3989
4037
|
How category leaders generate millions of high-converting pages without server saturation:
|
|
3990
4038
|
|
|
@@ -3996,18 +4044,18 @@ How category leaders generate millions of high-converting pages without server s
|
|
|
3996
4044
|
|
|
3997
4045
|
2. **The 4 Pillars of Zero-Latency (< 0.05ms) Resolution:**
|
|
3998
4046
|
- **0 Bytes in Database:** Never generate physical static files or query heavy databases per request. Pages are resolved mathematically in RAM upon arrival.
|
|
3999
|
-
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\`
|
|
4000
|
-
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge
|
|
4047
|
+
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\` handles all matrices through one lightweight layout.
|
|
4048
|
+
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge on first request.
|
|
4001
4049
|
- **Automatic Siloing & Mesh Linking:**
|
|
4002
4050
|
- Links to 3 neighboring geographic cities for the same service.
|
|
4003
4051
|
- Links to 4 related professions/industries in the same target category.
|
|
4004
4052
|
- Complete Schema.org BreadcrumbList navigation.
|
|
4005
|
-
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index
|
|
4053
|
+
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index.
|
|
4006
4054
|
- **Dynamic \`/llms.txt\` Feed:** High-density Markdown stream enabling direct indexing by ChatGPT Search & Perplexity.
|
|
4007
4055
|
|
|
4008
4056
|
---
|
|
4009
4057
|
|
|
4010
|
-
### \uD83D\uDEE0️
|
|
4058
|
+
### \uD83D\uDEE0️ 5. AI AGENT IMPLEMENTATION PROTOCOL (STEP-BY-STEP)
|
|
4011
4059
|
|
|
4012
4060
|
When setting up programmatic SEO in any codebase, the AI Agent MUST generate these exact 4 files:
|
|
4013
4061
|
|
|
@@ -4020,6 +4068,7 @@ export const matrixEngine = new PseoMatrixEngine();
|
|
|
4020
4068
|
export const SEO_CONFIG = {
|
|
4021
4069
|
brandName: "Acme",
|
|
4022
4070
|
language: "en",
|
|
4071
|
+
cleanDirectRoutes: true, // Eliminates parasite words (/solutions/, etc.)
|
|
4023
4072
|
minPopulationToIndex: 15_000,
|
|
4024
4073
|
};
|
|
4025
4074
|
|
|
@@ -4027,19 +4076,23 @@ export const SEO_CONFIG = {
|
|
|
4027
4076
|
export const PSEO_DATASET = {
|
|
4028
4077
|
services: [
|
|
4029
4078
|
// 1 per major frontend feature branch
|
|
4030
|
-
{ slug: "
|
|
4079
|
+
{ slug: "autopost-facebook", name: "Autopost Facebook & Instagram", category: "Social Media", keyFeatures: ["AI Scheduling", "Visual Calendar", "Auto-Hashtags"], description: "Automated social media posting engine" },
|
|
4080
|
+
],
|
|
4081
|
+
locations: [
|
|
4082
|
+
{ slug: "paris", name: "Paris", region: "Île-de-France", country: "France", population: 2_161_000, currency: "EUR", currencySymbol: "€" },
|
|
4083
|
+
{ slug: "lyon", name: "Lyon", region: "Rhône-Alpes", country: "France", population: 522_000, currency: "EUR", currencySymbol: "€" },
|
|
4031
4084
|
],
|
|
4032
4085
|
targets: [
|
|
4033
|
-
{ slug: "
|
|
4086
|
+
{ slug: "agences", name: "Marketing Agencies", type: "industry", painPoints: ["Manual Posting"], benefits: ["10x Output"] },
|
|
4034
4087
|
],
|
|
4035
4088
|
integrations: [
|
|
4036
|
-
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["
|
|
4089
|
+
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["Catalog sync"] },
|
|
4037
4090
|
],
|
|
4038
4091
|
templates: [
|
|
4039
|
-
{ slug: "
|
|
4092
|
+
{ slug: "social-calendar-excel", title: "Social Media Calendar", topic: "Social Media", format: "excel", benefits: ["Instant setup"] },
|
|
4040
4093
|
],
|
|
4041
4094
|
glossaryTerms: [
|
|
4042
|
-
{ slug: "
|
|
4095
|
+
{ slug: "engagement-rate", term: "Engagement Rate", shortDefinition: "Percentage of audience interacting with content" },
|
|
4043
4096
|
],
|
|
4044
4097
|
};
|
|
4045
4098
|
\`\`\`
|
|
@@ -4052,19 +4105,15 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
4052
4105
|
import { renderBrandIconSvg } from "@lynxflow/seo-engine";
|
|
4053
4106
|
|
|
4054
4107
|
export async function generateMetadata({ params }: { params: { slug: string[] } }) {
|
|
4055
|
-
const path = "/" + params.slug.join("/");
|
|
4056
4108
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4057
|
-
const
|
|
4058
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
4109
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
4059
4110
|
if (!page) return {};
|
|
4060
4111
|
return { title: page.title, description: page.description, alternates: { canonical: page.canonicalUrl }, robots: page.robots };
|
|
4061
4112
|
}
|
|
4062
4113
|
|
|
4063
4114
|
export default async function ProgrammaticPage({ params }: { params: { slug: string[] } }) {
|
|
4064
|
-
const path = "/" + params.slug.join("/");
|
|
4065
4115
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
4066
|
-
const
|
|
4067
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
4116
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
4068
4117
|
if (!page) notFound();
|
|
4069
4118
|
|
|
4070
4119
|
// Automatic Brand Icon Detection
|
package/dist/index.mjs
CHANGED
|
@@ -3169,7 +3169,7 @@ class PseoMatrixEngine {
|
|
|
3169
3169
|
const countryCode = cleanSeoSlug(loc.country, { language: lang });
|
|
3170
3170
|
const citySlug = cleanSeoSlug(loc.slug, { language: lang });
|
|
3171
3171
|
const serviceSlug = cleanSeoSlug(s.slug, { language: lang });
|
|
3172
|
-
const urlPath = `${prefix}/${serviceSlug}/${countryCode}/${citySlug}`;
|
|
3172
|
+
const urlPath = options.cleanDirectRoutes !== false ? `/${serviceSlug}/${citySlug}` : `${prefix}/${serviceSlug}/${countryCode}/${citySlug}`;
|
|
3173
3173
|
const fullUrl = `${cleanDomain}${urlPath}`;
|
|
3174
3174
|
const isIndexed = (loc.population ?? 20000) >= minPop;
|
|
3175
3175
|
const robots = isIndexed ? "index, follow" : "noindex, follow";
|
|
@@ -3592,6 +3592,40 @@ class PseoMatrixEngine {
|
|
|
3592
3592
|
}
|
|
3593
3593
|
return allPages;
|
|
3594
3594
|
}
|
|
3595
|
+
resolvePage(slugOrPath, domain, data, options) {
|
|
3596
|
+
const path = typeof slugOrPath === "string" ? slugOrPath.startsWith("/") ? slugOrPath : `/${slugOrPath}` : `/${slugOrPath.join("/")}`;
|
|
3597
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3598
|
+
return pages.find((p) => p.urlPath === path);
|
|
3599
|
+
}
|
|
3600
|
+
generateSitemapXml(domain, data, options) {
|
|
3601
|
+
const pages = this.generateAllMatrices(domain, data, options).filter((p) => p.robots.includes("index"));
|
|
3602
|
+
const now = new Date().toISOString();
|
|
3603
|
+
const urls = pages.map((p) => ` <url>
|
|
3604
|
+
<loc>${p.canonicalUrl}</loc>
|
|
3605
|
+
<lastmod>${now}</lastmod>
|
|
3606
|
+
<changefreq>weekly</changefreq>
|
|
3607
|
+
<priority>0.8</priority>
|
|
3608
|
+
</url>`).join(`
|
|
3609
|
+
`);
|
|
3610
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3611
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3612
|
+
${urls}
|
|
3613
|
+
</urlset>`;
|
|
3614
|
+
}
|
|
3615
|
+
generateLlmsTxt(domain, data, options) {
|
|
3616
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
3617
|
+
const lines = [
|
|
3618
|
+
`# ${options.brandName} — AI Knowledge Graph & Page Hub`,
|
|
3619
|
+
`> Complete index of services, tools, integrations, and local solution hubs.`,
|
|
3620
|
+
"",
|
|
3621
|
+
`## Indexed Programmatic Hubs (${pages.length} Pages)`
|
|
3622
|
+
];
|
|
3623
|
+
for (const p of pages) {
|
|
3624
|
+
lines.push(`- [${p.h1}](${p.canonicalUrl}): ${p.description}`);
|
|
3625
|
+
}
|
|
3626
|
+
return lines.join(`
|
|
3627
|
+
`);
|
|
3628
|
+
}
|
|
3595
3629
|
}
|
|
3596
3630
|
// src/brand-icons.ts
|
|
3597
3631
|
var BRAND_ICONS = {
|
|
@@ -3881,7 +3915,21 @@ When discovering product modules, features, or services to build the SEO matrice
|
|
|
3881
3915
|
|
|
3882
3916
|
---
|
|
3883
3917
|
|
|
3884
|
-
### \
|
|
3918
|
+
### \uD83D\uDCCF 3. THE GOLDEN RULES OF URL ARCHITECTURE (MAX 3-4 SEGMENTS, ZERO PARASITE WORDS)
|
|
3919
|
+
|
|
3920
|
+
- **Rule A (2 to 3 URL Segments Ideal, 4 Maximum):**
|
|
3921
|
+
- ✅ **2 Segments (Top SEO Performance):** \`site.com/{service}/{city}\` (e.g. \`/autopost-facebook/lyon\`, \`/crm/paris\`).
|
|
3922
|
+
- ✅ **3 Segments (B2B Persona/Hub):** \`site.com/for/{target}/{city}\` or \`site.com/{locale}/{service}/{city}\`.
|
|
3923
|
+
- ❌ **Never 5 to 6 Segments:** Avoid \`/solutions/ai/autopost/facebook/fr/lyon\`.
|
|
3924
|
+
- **Rule B (Eliminate All Parasite Noise Words):**
|
|
3925
|
+
- Banish generic wrapper words like \`/solutions/\`, \`/pages/\`, \`/items/\`. Go direct to user search intent: What you do + Platform + Location.
|
|
3926
|
+
- **Rule C (The SDK Does 100% of the Heavy Lifting):**
|
|
3927
|
+
- The developer/AI only registers 3-4 product features and target cities in \`lib/seo.ts\`.
|
|
3928
|
+
- The SDK automatically resolves routes in memory via \`matrixEngine.resolvePage(params.slug)\`, generates complete Schema.org graphs (LocalBusiness, AggregateRating, AggregateOffer), creates AEO summaries, builds FAQ accordions, and manages mesh linking in < 0.05ms.
|
|
3929
|
+
|
|
3930
|
+
---
|
|
3931
|
+
|
|
3932
|
+
### \uD83C\uDFC6 4. THE ARCHITECTURAL PLAYBOOK OF SAAS TITANS (7M+ PAGES WITH 0 DB BOTTLENECKS)
|
|
3885
3933
|
|
|
3886
3934
|
How category leaders generate millions of high-converting pages without server saturation:
|
|
3887
3935
|
|
|
@@ -3893,18 +3941,18 @@ How category leaders generate millions of high-converting pages without server s
|
|
|
3893
3941
|
|
|
3894
3942
|
2. **The 4 Pillars of Zero-Latency (< 0.05ms) Resolution:**
|
|
3895
3943
|
- **0 Bytes in Database:** Never generate physical static files or query heavy databases per request. Pages are resolved mathematically in RAM upon arrival.
|
|
3896
|
-
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\`
|
|
3897
|
-
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge
|
|
3944
|
+
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\` handles all matrices through one lightweight layout.
|
|
3945
|
+
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge on first request.
|
|
3898
3946
|
- **Automatic Siloing & Mesh Linking:**
|
|
3899
3947
|
- Links to 3 neighboring geographic cities for the same service.
|
|
3900
3948
|
- Links to 4 related professions/industries in the same target category.
|
|
3901
3949
|
- Complete Schema.org BreadcrumbList navigation.
|
|
3902
|
-
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index
|
|
3950
|
+
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index.
|
|
3903
3951
|
- **Dynamic \`/llms.txt\` Feed:** High-density Markdown stream enabling direct indexing by ChatGPT Search & Perplexity.
|
|
3904
3952
|
|
|
3905
3953
|
---
|
|
3906
3954
|
|
|
3907
|
-
### \uD83D\uDEE0️
|
|
3955
|
+
### \uD83D\uDEE0️ 5. AI AGENT IMPLEMENTATION PROTOCOL (STEP-BY-STEP)
|
|
3908
3956
|
|
|
3909
3957
|
When setting up programmatic SEO in any codebase, the AI Agent MUST generate these exact 4 files:
|
|
3910
3958
|
|
|
@@ -3917,6 +3965,7 @@ export const matrixEngine = new PseoMatrixEngine();
|
|
|
3917
3965
|
export const SEO_CONFIG = {
|
|
3918
3966
|
brandName: "Acme",
|
|
3919
3967
|
language: "en",
|
|
3968
|
+
cleanDirectRoutes: true, // Eliminates parasite words (/solutions/, etc.)
|
|
3920
3969
|
minPopulationToIndex: 15_000,
|
|
3921
3970
|
};
|
|
3922
3971
|
|
|
@@ -3924,19 +3973,23 @@ export const SEO_CONFIG = {
|
|
|
3924
3973
|
export const PSEO_DATASET = {
|
|
3925
3974
|
services: [
|
|
3926
3975
|
// 1 per major frontend feature branch
|
|
3927
|
-
{ slug: "
|
|
3976
|
+
{ slug: "autopost-facebook", name: "Autopost Facebook & Instagram", category: "Social Media", keyFeatures: ["AI Scheduling", "Visual Calendar", "Auto-Hashtags"], description: "Automated social media posting engine" },
|
|
3977
|
+
],
|
|
3978
|
+
locations: [
|
|
3979
|
+
{ slug: "paris", name: "Paris", region: "Île-de-France", country: "France", population: 2_161_000, currency: "EUR", currencySymbol: "€" },
|
|
3980
|
+
{ slug: "lyon", name: "Lyon", region: "Rhône-Alpes", country: "France", population: 522_000, currency: "EUR", currencySymbol: "€" },
|
|
3928
3981
|
],
|
|
3929
3982
|
targets: [
|
|
3930
|
-
{ slug: "
|
|
3983
|
+
{ slug: "agences", name: "Marketing Agencies", type: "industry", painPoints: ["Manual Posting"], benefits: ["10x Output"] },
|
|
3931
3984
|
],
|
|
3932
3985
|
integrations: [
|
|
3933
|
-
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["
|
|
3986
|
+
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["Catalog sync"] },
|
|
3934
3987
|
],
|
|
3935
3988
|
templates: [
|
|
3936
|
-
{ slug: "
|
|
3989
|
+
{ slug: "social-calendar-excel", title: "Social Media Calendar", topic: "Social Media", format: "excel", benefits: ["Instant setup"] },
|
|
3937
3990
|
],
|
|
3938
3991
|
glossaryTerms: [
|
|
3939
|
-
{ slug: "
|
|
3992
|
+
{ slug: "engagement-rate", term: "Engagement Rate", shortDefinition: "Percentage of audience interacting with content" },
|
|
3940
3993
|
],
|
|
3941
3994
|
};
|
|
3942
3995
|
\`\`\`
|
|
@@ -3949,19 +4002,15 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
3949
4002
|
import { renderBrandIconSvg } from "@lynxflow/seo-engine";
|
|
3950
4003
|
|
|
3951
4004
|
export async function generateMetadata({ params }: { params: { slug: string[] } }) {
|
|
3952
|
-
const path = "/" + params.slug.join("/");
|
|
3953
4005
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
3954
|
-
const
|
|
3955
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
4006
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
3956
4007
|
if (!page) return {};
|
|
3957
4008
|
return { title: page.title, description: page.description, alternates: { canonical: page.canonicalUrl }, robots: page.robots };
|
|
3958
4009
|
}
|
|
3959
4010
|
|
|
3960
4011
|
export default async function ProgrammaticPage({ params }: { params: { slug: string[] } }) {
|
|
3961
|
-
const path = "/" + params.slug.join("/");
|
|
3962
4012
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
3963
|
-
const
|
|
3964
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
4013
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
3965
4014
|
if (!page) notFound();
|
|
3966
4015
|
|
|
3967
4016
|
// Automatic Brand Icon Detection
|
package/dist/matrix-engine.d.ts
CHANGED
|
@@ -127,6 +127,7 @@ export interface GeneratedPageMeta {
|
|
|
127
127
|
export interface MatrixOptions {
|
|
128
128
|
brandName: string;
|
|
129
129
|
language?: string;
|
|
130
|
+
cleanDirectRoutes?: boolean;
|
|
130
131
|
minPopulationToIndex?: number;
|
|
131
132
|
defaultCurrency?: string;
|
|
132
133
|
defaultCurrencySymbol?: string;
|
|
@@ -198,4 +199,27 @@ export declare class PseoMatrixEngine {
|
|
|
198
199
|
glossaryTerms?: PseoGlossaryTerm[];
|
|
199
200
|
calculators?: PseoCalculator[];
|
|
200
201
|
}, options: MatrixOptions): GeneratedPageMeta[];
|
|
202
|
+
/**
|
|
203
|
+
* Resolves a single page route in RAM in < 0.05ms.
|
|
204
|
+
* Matches string path or Next.js slug array.
|
|
205
|
+
*/
|
|
206
|
+
resolvePage(slugOrPath: string | string[], domain: string, data: {
|
|
207
|
+
services?: PseoService[];
|
|
208
|
+
locations?: PseoLocation[];
|
|
209
|
+
competitors?: PseoCompetitor[];
|
|
210
|
+
targets?: PseoTarget[];
|
|
211
|
+
integrations?: PseoIntegration[];
|
|
212
|
+
useCases?: PseoUseCase[];
|
|
213
|
+
templates?: PseoTemplate[];
|
|
214
|
+
glossaryTerms?: PseoGlossaryTerm[];
|
|
215
|
+
calculators?: PseoCalculator[];
|
|
216
|
+
}, options: MatrixOptions): GeneratedPageMeta | undefined;
|
|
217
|
+
/**
|
|
218
|
+
* Generates a fully formatted XML Sitemap string.
|
|
219
|
+
*/
|
|
220
|
+
generateSitemapXml(domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): string;
|
|
221
|
+
/**
|
|
222
|
+
* Generates an official /llms.txt Markdown directory for AI search bots.
|
|
223
|
+
*/
|
|
224
|
+
generateLlmsTxt(domain: string, data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1], options: MatrixOptions): string;
|
|
201
225
|
}
|
package/package.json
CHANGED
package/src/engine.test.ts
CHANGED
|
@@ -186,4 +186,35 @@ describe("Audited Reference Engines (Advertools, Santifer, Seonaut)", () => {
|
|
|
186
186
|
expect(offer["@type"]).toBe("AggregateOffer");
|
|
187
187
|
expect(offer.lowPrice).toBe("29");
|
|
188
188
|
});
|
|
189
|
+
|
|
190
|
+
it("PseoMatrixEngine: resolvePage returns complete page in < 0.05ms", () => {
|
|
191
|
+
const engine = new PseoMatrixEngine();
|
|
192
|
+
const page = engine.resolvePage(
|
|
193
|
+
["autopost-facebook", "lyon"],
|
|
194
|
+
"https://acme.com",
|
|
195
|
+
{
|
|
196
|
+
services: [{ slug: "autopost-facebook", name: "Autopost Facebook", category: "Social" }],
|
|
197
|
+
locations: [{ slug: "lyon", name: "Lyon", country: "France", population: 500_000 }],
|
|
198
|
+
},
|
|
199
|
+
{ brandName: "Acme", cleanDirectRoutes: true },
|
|
200
|
+
);
|
|
201
|
+
expect(page).toBeDefined();
|
|
202
|
+
expect(page?.urlPath).toBe("/autopost-facebook/lyon");
|
|
203
|
+
expect(page?.h1).toContain("Autopost Facebook");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("PseoMatrixEngine: generateSitemapXml and generateLlmsTxt generate complete feeds", () => {
|
|
207
|
+
const engine = new PseoMatrixEngine();
|
|
208
|
+
const data = {
|
|
209
|
+
services: [{ slug: "autopost", name: "Autopost", category: "Social" }],
|
|
210
|
+
locations: [{ slug: "paris", name: "Paris", country: "France", population: 2_000_000 }],
|
|
211
|
+
};
|
|
212
|
+
const sitemap = engine.generateSitemapXml("https://acme.com", data, { brandName: "Acme" });
|
|
213
|
+
expect(sitemap).toContain("<urlset");
|
|
214
|
+
expect(sitemap).toContain("<loc>https://acme.com/autopost/paris</loc>");
|
|
215
|
+
|
|
216
|
+
const llmsTxt = engine.generateLlmsTxt("https://acme.com", data, { brandName: "Acme" });
|
|
217
|
+
expect(llmsTxt).toContain("# Acme — AI Knowledge Graph");
|
|
218
|
+
expect(llmsTxt).toContain("https://acme.com/autopost/paris");
|
|
219
|
+
});
|
|
189
220
|
});
|
package/src/llm-prompt.ts
CHANGED
|
@@ -37,7 +37,21 @@ When discovering product modules, features, or services to build the SEO matrice
|
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
###
|
|
40
|
+
### 📏 3. THE GOLDEN RULES OF URL ARCHITECTURE (MAX 3-4 SEGMENTS, ZERO PARASITE WORDS)
|
|
41
|
+
|
|
42
|
+
- **Rule A (2 to 3 URL Segments Ideal, 4 Maximum):**
|
|
43
|
+
- ✅ **2 Segments (Top SEO Performance):** \`site.com/{service}/{city}\` (e.g. \`/autopost-facebook/lyon\`, \`/crm/paris\`).
|
|
44
|
+
- ✅ **3 Segments (B2B Persona/Hub):** \`site.com/for/{target}/{city}\` or \`site.com/{locale}/{service}/{city}\`.
|
|
45
|
+
- ❌ **Never 5 to 6 Segments:** Avoid \`/solutions/ai/autopost/facebook/fr/lyon\`.
|
|
46
|
+
- **Rule B (Eliminate All Parasite Noise Words):**
|
|
47
|
+
- Banish generic wrapper words like \`/solutions/\`, \`/pages/\`, \`/items/\`. Go direct to user search intent: What you do + Platform + Location.
|
|
48
|
+
- **Rule C (The SDK Does 100% of the Heavy Lifting):**
|
|
49
|
+
- The developer/AI only registers 3-4 product features and target cities in \`lib/seo.ts\`.
|
|
50
|
+
- The SDK automatically resolves routes in memory via \`matrixEngine.resolvePage(params.slug)\`, generates complete Schema.org graphs (LocalBusiness, AggregateRating, AggregateOffer), creates AEO summaries, builds FAQ accordions, and manages mesh linking in < 0.05ms.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
### 🏆 4. THE ARCHITECTURAL PLAYBOOK OF SAAS TITANS (7M+ PAGES WITH 0 DB BOTTLENECKS)
|
|
41
55
|
|
|
42
56
|
How category leaders generate millions of high-converting pages without server saturation:
|
|
43
57
|
|
|
@@ -49,18 +63,18 @@ How category leaders generate millions of high-converting pages without server s
|
|
|
49
63
|
|
|
50
64
|
2. **The 4 Pillars of Zero-Latency (< 0.05ms) Resolution:**
|
|
51
65
|
- **0 Bytes in Database:** Never generate physical static files or query heavy databases per request. Pages are resolved mathematically in RAM upon arrival.
|
|
52
|
-
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\`
|
|
53
|
-
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge
|
|
66
|
+
- **1 Single Universal Catch-All Route:** \`app/[...slug]/page.tsx\` handles all matrices through one lightweight layout.
|
|
67
|
+
- **Edge Caching & ISR:** The rendered HTML is instantly cached at the CDN/Edge on first request.
|
|
54
68
|
- **Automatic Siloing & Mesh Linking:**
|
|
55
69
|
- Links to 3 neighboring geographic cities for the same service.
|
|
56
70
|
- Links to 4 related professions/industries in the same target category.
|
|
57
71
|
- Complete Schema.org BreadcrumbList navigation.
|
|
58
|
-
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index
|
|
72
|
+
- **Sharded XML Sitemaps:** Split into 50,000 URL chunks with a master sitemap index.
|
|
59
73
|
- **Dynamic \`/llms.txt\` Feed:** High-density Markdown stream enabling direct indexing by ChatGPT Search & Perplexity.
|
|
60
74
|
|
|
61
75
|
---
|
|
62
76
|
|
|
63
|
-
### 🛠️
|
|
77
|
+
### 🛠️ 5. AI AGENT IMPLEMENTATION PROTOCOL (STEP-BY-STEP)
|
|
64
78
|
|
|
65
79
|
When setting up programmatic SEO in any codebase, the AI Agent MUST generate these exact 4 files:
|
|
66
80
|
|
|
@@ -73,6 +87,7 @@ export const matrixEngine = new PseoMatrixEngine();
|
|
|
73
87
|
export const SEO_CONFIG = {
|
|
74
88
|
brandName: "Acme",
|
|
75
89
|
language: "en",
|
|
90
|
+
cleanDirectRoutes: true, // Eliminates parasite words (/solutions/, etc.)
|
|
76
91
|
minPopulationToIndex: 15_000,
|
|
77
92
|
};
|
|
78
93
|
|
|
@@ -80,19 +95,23 @@ export const SEO_CONFIG = {
|
|
|
80
95
|
export const PSEO_DATASET = {
|
|
81
96
|
services: [
|
|
82
97
|
// 1 per major frontend feature branch
|
|
83
|
-
{ slug: "
|
|
98
|
+
{ slug: "autopost-facebook", name: "Autopost Facebook & Instagram", category: "Social Media", keyFeatures: ["AI Scheduling", "Visual Calendar", "Auto-Hashtags"], description: "Automated social media posting engine" },
|
|
99
|
+
],
|
|
100
|
+
locations: [
|
|
101
|
+
{ slug: "paris", name: "Paris", region: "Île-de-France", country: "France", population: 2_161_000, currency: "EUR", currencySymbol: "€" },
|
|
102
|
+
{ slug: "lyon", name: "Lyon", region: "Rhône-Alpes", country: "France", population: 522_000, currency: "EUR", currencySymbol: "€" },
|
|
84
103
|
],
|
|
85
104
|
targets: [
|
|
86
|
-
{ slug: "
|
|
105
|
+
{ slug: "agences", name: "Marketing Agencies", type: "industry", painPoints: ["Manual Posting"], benefits: ["10x Output"] },
|
|
87
106
|
],
|
|
88
107
|
integrations: [
|
|
89
|
-
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["
|
|
108
|
+
{ slug: "shopify", name: "Shopify", category: "E-Commerce", syncFeatures: ["Catalog sync"] },
|
|
90
109
|
],
|
|
91
110
|
templates: [
|
|
92
|
-
{ slug: "
|
|
111
|
+
{ slug: "social-calendar-excel", title: "Social Media Calendar", topic: "Social Media", format: "excel", benefits: ["Instant setup"] },
|
|
93
112
|
],
|
|
94
113
|
glossaryTerms: [
|
|
95
|
-
{ slug: "
|
|
114
|
+
{ slug: "engagement-rate", term: "Engagement Rate", shortDefinition: "Percentage of audience interacting with content" },
|
|
96
115
|
],
|
|
97
116
|
};
|
|
98
117
|
\`\`\`
|
|
@@ -105,19 +124,15 @@ import { matrixEngine, SEO_CONFIG, PSEO_DATASET } from "@/lib/seo";
|
|
|
105
124
|
import { renderBrandIconSvg } from "@lynxflow/seo-engine";
|
|
106
125
|
|
|
107
126
|
export async function generateMetadata({ params }: { params: { slug: string[] } }) {
|
|
108
|
-
const path = "/" + params.slug.join("/");
|
|
109
127
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
110
|
-
const
|
|
111
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
128
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
112
129
|
if (!page) return {};
|
|
113
130
|
return { title: page.title, description: page.description, alternates: { canonical: page.canonicalUrl }, robots: page.robots };
|
|
114
131
|
}
|
|
115
132
|
|
|
116
133
|
export default async function ProgrammaticPage({ params }: { params: { slug: string[] } }) {
|
|
117
|
-
const path = "/" + params.slug.join("/");
|
|
118
134
|
const domain = process.env.NEXT_PUBLIC_SITE_URL || "https://example.com";
|
|
119
|
-
const
|
|
120
|
-
const page = pages.find((p) => p.urlPath === path);
|
|
135
|
+
const page = matrixEngine.resolvePage(params.slug, domain, PSEO_DATASET, SEO_CONFIG);
|
|
121
136
|
if (!page) notFound();
|
|
122
137
|
|
|
123
138
|
// Automatic Brand Icon Detection
|
package/src/matrix-engine.ts
CHANGED
|
@@ -155,6 +155,7 @@ export interface GeneratedPageMeta {
|
|
|
155
155
|
export interface MatrixOptions {
|
|
156
156
|
brandName: string;
|
|
157
157
|
language?: string; // Default: "en", supports "fr", "de", "es", "pt", "it", etc.
|
|
158
|
+
cleanDirectRoutes?: boolean; // When true (default), eliminates parasite words (/solutions/, etc.) for direct /{service}/{city}
|
|
158
159
|
minPopulationToIndex?: number;
|
|
159
160
|
defaultCurrency?: string;
|
|
160
161
|
defaultCurrencySymbol?: string;
|
|
@@ -263,7 +264,10 @@ export class PseoMatrixEngine {
|
|
|
263
264
|
const citySlug = cleanSeoSlug(loc.slug, { language: lang });
|
|
264
265
|
const serviceSlug = cleanSeoSlug(s.slug, { language: lang });
|
|
265
266
|
|
|
266
|
-
|
|
267
|
+
// Zero parasite words: Direct /{service}/{city} or /{service}/{country}/{city} if specified
|
|
268
|
+
const urlPath = options.cleanDirectRoutes !== false
|
|
269
|
+
? `/${serviceSlug}/${citySlug}`
|
|
270
|
+
: `${prefix}/${serviceSlug}/${countryCode}/${citySlug}`;
|
|
267
271
|
const fullUrl = `${cleanDomain}${urlPath}`;
|
|
268
272
|
|
|
269
273
|
const isIndexed = (loc.population ?? 20_000) >= minPop;
|
|
@@ -815,4 +819,83 @@ export class PseoMatrixEngine {
|
|
|
815
819
|
|
|
816
820
|
return allPages;
|
|
817
821
|
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Resolves a single page route in RAM in < 0.05ms.
|
|
825
|
+
* Matches string path or Next.js slug array.
|
|
826
|
+
*/
|
|
827
|
+
resolvePage(
|
|
828
|
+
slugOrPath: string | string[],
|
|
829
|
+
domain: string,
|
|
830
|
+
data: {
|
|
831
|
+
services?: PseoService[];
|
|
832
|
+
locations?: PseoLocation[];
|
|
833
|
+
competitors?: PseoCompetitor[];
|
|
834
|
+
targets?: PseoTarget[];
|
|
835
|
+
integrations?: PseoIntegration[];
|
|
836
|
+
useCases?: PseoUseCase[];
|
|
837
|
+
templates?: PseoTemplate[];
|
|
838
|
+
glossaryTerms?: PseoGlossaryTerm[];
|
|
839
|
+
calculators?: PseoCalculator[];
|
|
840
|
+
},
|
|
841
|
+
options: MatrixOptions,
|
|
842
|
+
): GeneratedPageMeta | undefined {
|
|
843
|
+
const path = typeof slugOrPath === "string"
|
|
844
|
+
? (slugOrPath.startsWith("/") ? slugOrPath : `/${slugOrPath}`)
|
|
845
|
+
: `/${slugOrPath.join("/")}`;
|
|
846
|
+
|
|
847
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
848
|
+
return pages.find((p) => p.urlPath === path);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Generates a fully formatted XML Sitemap string.
|
|
853
|
+
*/
|
|
854
|
+
generateSitemapXml(
|
|
855
|
+
domain: string,
|
|
856
|
+
data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1],
|
|
857
|
+
options: MatrixOptions,
|
|
858
|
+
): string {
|
|
859
|
+
const pages = this.generateAllMatrices(domain, data, options).filter((p) => p.robots.includes("index"));
|
|
860
|
+
const now = new Date().toISOString();
|
|
861
|
+
|
|
862
|
+
const urls = pages
|
|
863
|
+
.map(
|
|
864
|
+
(p) => ` <url>
|
|
865
|
+
<loc>${p.canonicalUrl}</loc>
|
|
866
|
+
<lastmod>${now}</lastmod>
|
|
867
|
+
<changefreq>weekly</changefreq>
|
|
868
|
+
<priority>0.8</priority>
|
|
869
|
+
</url>`,
|
|
870
|
+
)
|
|
871
|
+
.join("\n");
|
|
872
|
+
|
|
873
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
874
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
875
|
+
${urls}
|
|
876
|
+
</urlset>`;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Generates an official /llms.txt Markdown directory for AI search bots.
|
|
881
|
+
*/
|
|
882
|
+
generateLlmsTxt(
|
|
883
|
+
domain: string,
|
|
884
|
+
data: Parameters<PseoMatrixEngine["generateAllMatrices"]>[1],
|
|
885
|
+
options: MatrixOptions,
|
|
886
|
+
): string {
|
|
887
|
+
const pages = this.generateAllMatrices(domain, data, options);
|
|
888
|
+
const lines: string[] = [
|
|
889
|
+
`# ${options.brandName} — AI Knowledge Graph & Page Hub`,
|
|
890
|
+
`> Complete index of services, tools, integrations, and local solution hubs.`,
|
|
891
|
+
"",
|
|
892
|
+
`## Indexed Programmatic Hubs (${pages.length} Pages)`,
|
|
893
|
+
];
|
|
894
|
+
|
|
895
|
+
for (const p of pages) {
|
|
896
|
+
lines.push(`- [${p.h1}](${p.canonicalUrl}): ${p.description}`);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return lines.join("\n");
|
|
900
|
+
}
|
|
818
901
|
}
|