Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compare-mockserver.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
}
}
</script>
<link rel="canonical" href="https://mockforge.dev/compare-mockserver.html" />
</head>
<body class="bg-surface-subtle text-text-primary antialiased selection:bg-brand-orange/20">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
Expand Down
1 change: 1 addition & 0 deletions compare-postman-mock.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
}
}
</script>
<link rel="canonical" href="https://mockforge.dev/compare-postman-mock.html" />
</head>
<body class="bg-surface-subtle text-text-primary antialiased selection:bg-brand-orange/20">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
Expand Down
1 change: 1 addition & 0 deletions compare-wiremock.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
}
}
</script>
<link rel="canonical" href="https://mockforge.dev/compare-wiremock.html" />
</head>
<body class="bg-surface-subtle text-text-primary antialiased selection:bg-brand-orange/20">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
Expand Down
1 change: 1 addition & 0 deletions contact.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
}
}
</script>
<link rel="canonical" href="https://mockforge.dev/contact.html" />
</head>
<body class="bg-surface-subtle dark:bg-gray-900 text-text-primary dark:text-gray-100 antialiased">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
Expand Down
3 changes: 2 additions & 1 deletion engineering-notes.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@
}
}
</script>
</head>
<link rel="canonical" href="https://mockforge.dev/engineering-notes.html" />
</head>
<body class="bg-surface-subtle text-text-primary antialiased font-sans selection:bg-brand-orange/20">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
Expand Down
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ <h1 class="text-4xl md:text-5xl lg:text-[3.25rem] font-semibold leading-[1.05] t
Star on GitHub
</a>
</div>
<a href="https://github.com/SaaSy-Solutions/mockforge" class="mt-4 inline-flex rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-brand-orange" aria-label="View MockForge stars on GitHub">
<img src="https://img.shields.io/github/stars/SaaSy-Solutions/mockforge?style=social" alt="MockForge GitHub stars" width="110" height="20" style="object-fit: contain" decoding="async" />
</a>
<!-- Runnable OpenAPI example, followed by the request that verifies it. -->
<div class="mt-7 max-w-xl">
<p class="mb-2 text-sm text-text-secondary">Run the example with Docker:</p>
Expand Down
1 change: 1 addition & 0 deletions privacy.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
}
}
</script>
<link rel="canonical" href="https://mockforge.dev/privacy.html" />
</head>
<body class="bg-surface-subtle dark:bg-gray-900 text-text-primary dark:text-gray-100 antialiased">
<header class="sticky top-0 z-40 backdrop-blur bg-white/90 dark:bg-slate-900 border-b border-black/5 dark:border-white/10">
Expand Down
238 changes: 43 additions & 195 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -1,198 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://mockforge.dev/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://mockforge.dev/pricing.html</loc>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://mockforge.dev/engineering-notes.html</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://mockforge.dev/compare-wiremock.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/compare-mockserver.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/compare-postman-mock.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/note-cloud-launch.html</loc>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://mockforge.dev/note-grpc-mocking-in-ci.html</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://mockforge.dev/note-why-multi-protocol.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/note-mocking-kafka-without-broker.html</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://mockforge.dev/note-when-wiremock-isnt-enough.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/note-cost-cap-design.html</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://mockforge.dev/note-our-saas-infrastructure.html</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://mockforge.dev/note-announcing-v1.html</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://mockforge.dev/note-api-drift-detection-and-contract-alerting.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-client-generation-tradeoffs.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-conformance-testing.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-migration-from-static-fixtures.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-multi-target-conformance-and-real-world-specs.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-release-cadence-and-risk.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-reliability-update-march-2026.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-reliability-updates-conformance-and-admin.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-scenario-switching.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-security-guardrails-v0-2x.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-spec-driven-openapi-conformance.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-testing-failure-paths.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-1-3-protocol-expansion.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-0-client-generation.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-3-bug-fixes.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-4-client-fixes.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-5-enterprise-security.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-6-security-infrastructure.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-2-7-api-sync-tcp.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-v0-3-migration-playbook.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-wafbench-security-hardening.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/note-wafbench-sqli-detection.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://mockforge.dev/contact.html</loc>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://mockforge.dev/privacy.html</loc>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://mockforge.dev/trust.html</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
<url><loc>https://mockforge.dev/</loc></url>
<url><loc>https://mockforge.dev/compare-mockserver.html</loc></url>
<url><loc>https://mockforge.dev/compare-postman-mock.html</loc></url>
<url><loc>https://mockforge.dev/compare-wiremock.html</loc></url>
<url><loc>https://mockforge.dev/engineering-notes.html</loc></url>
<url><loc>https://mockforge.dev/note-announcing-v1.html</loc></url>
<url><loc>https://mockforge.dev/note-api-drift-detection-and-contract-alerting.html</loc></url>
<url><loc>https://mockforge.dev/note-client-generation-tradeoffs.html</loc></url>
<url><loc>https://mockforge.dev/note-cloud-launch.html</loc></url>
<url><loc>https://mockforge.dev/note-conformance-maturity.html</loc></url>
<url><loc>https://mockforge.dev/note-conformance-testing.html</loc></url>
<url><loc>https://mockforge.dev/note-cost-cap-design.html</loc></url>
<url><loc>https://mockforge.dev/note-fault-injection-patterns.html</loc></url>
<url><loc>https://mockforge.dev/note-grpc-dynamic-routing-release.html</loc></url>
<url><loc>https://mockforge.dev/note-grpc-mocking-in-ci.html</loc></url>
<url><loc>https://mockforge.dev/note-migration-from-static-fixtures.html</loc></url>
<url><loc>https://mockforge.dev/note-mocking-kafka-without-broker.html</loc></url>
<url><loc>https://mockforge.dev/note-multi-target-conformance-and-real-world-specs.html</loc></url>
<url><loc>https://mockforge.dev/note-our-saas-infrastructure.html</loc></url>
<url><loc>https://mockforge.dev/note-release-cadence-and-risk.html</loc></url>
<url><loc>https://mockforge.dev/note-reliability-update-march-2026.html</loc></url>
<url><loc>https://mockforge.dev/note-reliability-updates-conformance-and-admin.html</loc></url>
<url><loc>https://mockforge.dev/note-scenario-switching.html</loc></url>
<url><loc>https://mockforge.dev/note-security-guardrails-v0-2x.html</loc></url>
<url><loc>https://mockforge.dev/note-spec-driven-openapi-conformance.html</loc></url>
<url><loc>https://mockforge.dev/note-testing-failure-paths.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-1-3-protocol-expansion.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-0-client-generation.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-3-bug-fixes.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-4-client-fixes.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-5-enterprise-security.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-6-security-infrastructure.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-2-7-api-sync-tcp.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-3-227-release.html</loc></url>
<url><loc>https://mockforge.dev/note-v0-3-migration-playbook.html</loc></url>
<url><loc>https://mockforge.dev/note-vs-postman-mock.html</loc></url>
<url><loc>https://mockforge.dev/note-wafbench-security-hardening.html</loc></url>
<url><loc>https://mockforge.dev/note-wafbench-sqli-detection.html</loc></url>
<url><loc>https://mockforge.dev/note-wasm-plugins.html</loc></url>
<url><loc>https://mockforge.dev/note-when-wiremock-isnt-enough.html</loc></url>
<url><loc>https://mockforge.dev/note-why-multi-protocol.html</loc></url>
<url><loc>https://mockforge.dev/pricing.html</loc></url>
<url><loc>https://mockforge.dev/trust.html</loc></url>
</urlset>
37 changes: 36 additions & 1 deletion scripts/build-pages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env node

Check warning on line 1 in scripts/build-pages.js

View check run for this annotation

CodeDig.ai / CodeDig PR Analysis

High complexity in scripts/build-pages.js

Cyclomatic complexity spike detected: scripts/build-pages.js (complexity: 12, delta: +6)
Raw output
Consider refactoring to reduce complexity. Extract methods, simplify conditionals, or use polymorphism to replace complex branching.

// Build src/pages/*.html → root *.html by substituting shared placeholder
// blocks. By default this script REFUSES to overwrite a root file when its
Expand Down Expand Up @@ -569,6 +569,9 @@
}
}

const sitemapUrls = new Set();
const siteOrigin = 'https://mockforge.dev';

for (const file of pageFiles) {
const config = getPageConfig(file);
let text = fs.readFileSync(path.join(sourceRoot, file), 'utf8');
Expand Down Expand Up @@ -597,9 +600,38 @@
}
}

// Indexable pages use their actual canonical URL; redirects and the 404
// page are excluded. Generating this during each build keeps new notes
// discoverable without maintaining a second hand-written page list.
if (file !== '404.html') {
const canonicalTags = [...text.matchAll(/<link\b(?=[^>]*\brel=["']canonical["'])[^>]*\bhref=["']([^"']+)["'][^>]*>/gi)];
if (canonicalTags.length > 1) {
throw new Error(`Multiple canonical URLs in ${file}`);
}
const canonical = canonicalTags.length
? canonicalTags[0][1]
: `${siteOrigin}/${file === 'index.html' ? '' : file}`;
const url = new URL(canonical);
if (url.origin !== siteOrigin || url.search || url.hash) {
throw new Error(`Invalid canonical URL in ${file}`);
}
if (canonicalTags.length === 0) {
text = text.replace('</head>', ` <link rel="canonical" href="${escapeHtmlAttr(canonical)}" />\n </head>`);
}
const noindex = /<meta\b(?=[^>]*\bname=["'](?:robots|googlebot)["'])[^>]*\bcontent=["'][^"']*\bnoindex\b/gi.test(text);
if (!noindex) sitemapUrls.add(url.href);
}

emit(file, text);
}

const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${[...sitemapUrls].sort().map(url => ` <url><loc>${escapeXml(url)}</loc></url>`).join('\n')}
</urlset>
`;
emit('public/sitemap.xml', sitemap);

for (const [file, redirect] of Object.entries(REDIRECTS)) {
if (pageFiles.includes(file)) {
throw new Error(`Redirect ${file} collides with src/pages/${file}`);
Expand All @@ -619,10 +651,13 @@
fs.copyFileSync(cnamePath, path.join(outputRoot, 'CNAME'));
}

fs.writeFileSync(path.join(outputRoot, 'public', 'sitemap.xml'), sitemap);
fs.writeFileSync(path.join(outputRoot, 'sitemap.xml'), sitemap);

// Serve agent/SEO discovery files from the dist root, not only under
// /public/. Scanners and agents expect /robots.txt, /sitemap.xml,
// /llms.txt, /openapi.json, and /openapi.registry.json at the domain root.
for (const rootAsset of ['robots.txt', 'sitemap.xml', 'llms.txt', 'openapi.json', 'openapi.registry.json']) {
for (const rootAsset of ['robots.txt', 'llms.txt', 'openapi.json', 'openapi.registry.json']) {
const assetPath = path.join(projectRoot, 'public', rootAsset);
if (fs.existsSync(assetPath)) {
fs.copyFileSync(assetPath, path.join(outputRoot, rootAsset));
Expand Down
3 changes: 3 additions & 0 deletions src/pages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ <h1 class="text-4xl md:text-5xl lg:text-[3.25rem] font-semibold leading-[1.05] t
Star on GitHub
</a>
</div>
<a href="https://github.com/SaaSy-Solutions/mockforge" class="mt-4 inline-flex rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-brand-orange" aria-label="View MockForge stars on GitHub">
<img src="https://img.shields.io/github/stars/SaaSy-Solutions/mockforge?style=social" alt="MockForge GitHub stars" width="110" height="20" style="object-fit: contain" decoding="async" />
</a>
<!-- Runnable OpenAPI example, followed by the request that verifies it. -->
<div class="mt-7 max-w-xl">
<p class="mb-2 text-sm text-text-secondary">Run the example with Docker:</p>
Expand Down
Loading