git-paid 0.0.0-stage → 2.1.0
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/bin/git-paid.js +211 -0
- package/brand/README.md +54 -0
- package/brand/postbuild-icon.png +0 -0
- package/brand/postbuild-icon.svg +14 -0
- package/brand/postbuild-logo.png +0 -0
- package/brand/postbuild-logo.svg +17 -0
- package/lib/auth.js +208 -0
- package/lib/directories.js +123 -0
- package/lib/engine.js +502 -0
- package/lib/fixer.js +168 -0
- package/lib/inbox.js +216 -0
- package/lib/mcp.js +907 -0
- package/lib/pseo.js +491 -0
- package/lib/stateful-mcp.js +485 -0
- package/lib/stripe.js +554 -0
- package/lib/submitter.js +189 -0
- package/package.json +42 -4
- package/server.js +252 -0
- package/README.md +0 -3
package/lib/pseo.js
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
function escapeHtml(str) {
|
|
5
|
+
return String(str || "")
|
|
6
|
+
.replace(/&/g, "&")
|
|
7
|
+
.replace(/</g, "<")
|
|
8
|
+
.replace(/>/g, ">")
|
|
9
|
+
.replace(/"/g, """);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function humanizeSlug(routePath, cleanName = "postbuild") {
|
|
13
|
+
const parts = String(routePath || "").split("/").filter(Boolean);
|
|
14
|
+
const category = parts[0] || "guides";
|
|
15
|
+
const pageSlug = parts[1] || "overview";
|
|
16
|
+
|
|
17
|
+
const words = pageSlug
|
|
18
|
+
.split("-")
|
|
19
|
+
.map((w) => {
|
|
20
|
+
if (w.toLowerCase() === cleanName.toLowerCase()) return cleanName;
|
|
21
|
+
if (w === "seo") return "SEO";
|
|
22
|
+
if (w === "pseo") return "Programmatic SEO";
|
|
23
|
+
if (w === "roi") return "ROI";
|
|
24
|
+
if (w === "api") return "API";
|
|
25
|
+
if (w === "ai") return "AI";
|
|
26
|
+
if (w === "saas") return "SaaS";
|
|
27
|
+
if (w === "cli") return "CLI";
|
|
28
|
+
if (w === "nextjs") return "Next.js";
|
|
29
|
+
if (w === "vs") return "vs.";
|
|
30
|
+
return w.charAt(0).toUpperCase() + w.slice(1);
|
|
31
|
+
})
|
|
32
|
+
.join(" ");
|
|
33
|
+
|
|
34
|
+
const categoryLabel =
|
|
35
|
+
{
|
|
36
|
+
"use-cases": "Use Case Architecture",
|
|
37
|
+
compare: "Technical Comparison",
|
|
38
|
+
templates: "Starter Kit & Boilerplate",
|
|
39
|
+
alternatives: "Ecosystem Evaluation",
|
|
40
|
+
calculators: "Interactive ROI Model",
|
|
41
|
+
guides: "Implementation Guide",
|
|
42
|
+
checklists: "Launch Verification Checklist"
|
|
43
|
+
}[category] || "Developer Guide";
|
|
44
|
+
|
|
45
|
+
return { category, categoryLabel, title: words };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Generates a complete, indexable, light-mode HTML landing page for a Programmatic SEO route.
|
|
50
|
+
*/
|
|
51
|
+
export function renderSinglePseoPage(page, allPages = [], options = {}) {
|
|
52
|
+
const origin = (options.origin || "https://postbuild.dev").replace(/\/$/, "");
|
|
53
|
+
const cleanName = options.cleanName || "postbuild";
|
|
54
|
+
const domain = options.domain || "postbuild.dev";
|
|
55
|
+
const { category, categoryLabel, title } = humanizeSlug(page.path, cleanName);
|
|
56
|
+
|
|
57
|
+
const fullTitle = `${title} — ${categoryLabel} | ${cleanName}`;
|
|
58
|
+
const canonicalUrl = `${origin}${page.path}`;
|
|
59
|
+
const metaDescription = `Complete ${new Date().getFullYear()} ${categoryLabel.toLowerCase()} for ${page.keyword}. Automate 25 programmatic SEO routes, provision a @postbuild.dev verification inbox, and dispatch to 85 directories with git paid.`;
|
|
60
|
+
|
|
61
|
+
const relatedPages = allPages.filter((p) => p.path !== page.path).slice(0, 8);
|
|
62
|
+
|
|
63
|
+
const jsonLd = {
|
|
64
|
+
"@context": "https://schema.org",
|
|
65
|
+
"@graph": [
|
|
66
|
+
{
|
|
67
|
+
"@type": "SoftwareApplication",
|
|
68
|
+
name: cleanName,
|
|
69
|
+
url: origin,
|
|
70
|
+
applicationCategory: "DeveloperApplication",
|
|
71
|
+
operatingSystem: "Web, macOS, Windows, Linux",
|
|
72
|
+
description: metaDescription,
|
|
73
|
+
offers: {
|
|
74
|
+
"@type": "Offer",
|
|
75
|
+
price: "29.00",
|
|
76
|
+
priceCurrency: "USD"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"@type": "BreadcrumbList",
|
|
81
|
+
itemListElement: [
|
|
82
|
+
{ "@type": "ListItem", position: 1, name: cleanName, item: origin },
|
|
83
|
+
{ "@type": "ListItem", position: 2, name: categoryLabel, item: `${origin}${page.path}` }
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"@type": "FAQPage",
|
|
88
|
+
mainEntity: [
|
|
89
|
+
{
|
|
90
|
+
"@type": "Question",
|
|
91
|
+
name: `How does ${cleanName} automate ${page.keyword}?`,
|
|
92
|
+
acceptedAnswer: {
|
|
93
|
+
"@type": "Answer",
|
|
94
|
+
text: `By running npx git-paid (or connecting the Postbuild MCP server to Claude Code, Cursor, or Gemini), ${cleanName} audits your live domain, synthesizes 25 programmatic SEO routes, provisions a dedicated @postbuild.dev verification inbox, and dispatches your launch kit across 85 curated directories.`
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"@type": "Question",
|
|
99
|
+
name: `Why use a Stateful MCP server for post-build SEO and directory dispatch?`,
|
|
100
|
+
acceptedAnswer: {
|
|
101
|
+
"@type": "Answer",
|
|
102
|
+
text: `Postbuild MCP uses watermark context residuals (unchanged@vN) and an in-memory superset cache to reduce multi-turn agent token consumption by over 75% while enforcing Two-Phase Cryptographic Optimistic Concurrency Control (OCC) before dispatching live directory submissions.`
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return `<!DOCTYPE html>
|
|
111
|
+
<html lang="en">
|
|
112
|
+
<head>
|
|
113
|
+
<meta charset="UTF-8" />
|
|
114
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
115
|
+
<title>${escapeHtml(fullTitle)}</title>
|
|
116
|
+
<meta name="description" content="${escapeHtml(metaDescription)}" />
|
|
117
|
+
<link rel="canonical" href="${escapeHtml(canonicalUrl)}" />
|
|
118
|
+
<meta property="og:type" content="article" />
|
|
119
|
+
<meta property="og:site_name" content="${escapeHtml(cleanName)}" />
|
|
120
|
+
<meta property="og:title" content="${escapeHtml(fullTitle)}" />
|
|
121
|
+
<meta property="og:description" content="${escapeHtml(metaDescription)}" />
|
|
122
|
+
<meta property="og:url" content="${escapeHtml(canonicalUrl)}" />
|
|
123
|
+
<meta property="og:image" content="${escapeHtml(origin)}/og-card.png" />
|
|
124
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
125
|
+
<meta name="twitter:title" content="${escapeHtml(fullTitle)}" />
|
|
126
|
+
<meta name="twitter:description" content="${escapeHtml(metaDescription)}" />
|
|
127
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%2309090B'/%3E%3Crect x='6' y='7' width='8' height='8' rx='2' stroke='%23FFFFFF' stroke-width='2.2' fill='none'/%3E%3Crect x='6' y='17' width='8' height='8' rx='2' stroke='%23FFFFFF' stroke-width='2.2' opacity='0.5' fill='none'/%3E%3Cpath d='M18 11H26M26 11L22.8 7.8M26 11L22.8 14.2' stroke='%2338BDF8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Ccircle cx='22' cy='21' r='2.8' fill='%23FFFFFF'/%3E%3C/svg%3E" />
|
|
128
|
+
<script type="application/ld+json">${JSON.stringify(jsonLd)}</script>
|
|
129
|
+
<style>
|
|
130
|
+
:root {
|
|
131
|
+
--bg: #fafafa;
|
|
132
|
+
--surface: #ffffff;
|
|
133
|
+
--text: #09090b;
|
|
134
|
+
--muted: #52525b;
|
|
135
|
+
--subtle: #71717a;
|
|
136
|
+
--border: #e4e4e7;
|
|
137
|
+
--accent: #0284c7;
|
|
138
|
+
--accent-soft: #f0f9ff;
|
|
139
|
+
--emerald: #059669;
|
|
140
|
+
--emerald-soft: #ecfdf5;
|
|
141
|
+
}
|
|
142
|
+
* { box-sizing: border-box; }
|
|
143
|
+
html, body {
|
|
144
|
+
margin: 0;
|
|
145
|
+
padding: 0;
|
|
146
|
+
background: var(--bg);
|
|
147
|
+
color: var(--text);
|
|
148
|
+
font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto, sans-serif;
|
|
149
|
+
line-height: 1.6;
|
|
150
|
+
-webkit-text-size-adjust: 100%;
|
|
151
|
+
text-size-adjust: 100%;
|
|
152
|
+
}
|
|
153
|
+
.container {
|
|
154
|
+
max-width: 980px;
|
|
155
|
+
margin: 0 auto;
|
|
156
|
+
padding: 24px 20px 72px;
|
|
157
|
+
}
|
|
158
|
+
.topbar {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
justify-content: space-between;
|
|
162
|
+
padding: 14px 0 28px;
|
|
163
|
+
border-bottom: 1px solid var(--border);
|
|
164
|
+
margin-bottom: 36px;
|
|
165
|
+
gap: 12px;
|
|
166
|
+
flex-wrap: wrap;
|
|
167
|
+
}
|
|
168
|
+
.brand {
|
|
169
|
+
display: inline-flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
gap: 10px;
|
|
172
|
+
text-decoration: none;
|
|
173
|
+
color: var(--text);
|
|
174
|
+
font-weight: 700;
|
|
175
|
+
font-size: 16px;
|
|
176
|
+
letter-spacing: -0.02em;
|
|
177
|
+
}
|
|
178
|
+
.brand-badge {
|
|
179
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
180
|
+
font-size: 11px;
|
|
181
|
+
font-weight: 600;
|
|
182
|
+
padding: 2px 8px;
|
|
183
|
+
border-radius: 999px;
|
|
184
|
+
background: #f4f4f5;
|
|
185
|
+
color: var(--muted);
|
|
186
|
+
border: 1px solid var(--border);
|
|
187
|
+
}
|
|
188
|
+
.cta-btn {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
gap: 8px;
|
|
192
|
+
background: var(--text);
|
|
193
|
+
color: #ffffff;
|
|
194
|
+
text-decoration: none;
|
|
195
|
+
padding: 9px 16px;
|
|
196
|
+
border-radius: 8px;
|
|
197
|
+
font-size: 13px;
|
|
198
|
+
font-weight: 600;
|
|
199
|
+
transition: opacity 0.15s ease;
|
|
200
|
+
}
|
|
201
|
+
.cta-btn:hover { opacity: 0.9; }
|
|
202
|
+
.pill-row {
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-wrap: wrap;
|
|
205
|
+
gap: 8px;
|
|
206
|
+
margin-bottom: 14px;
|
|
207
|
+
}
|
|
208
|
+
.pill {
|
|
209
|
+
display: inline-flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
gap: 6px;
|
|
212
|
+
font-size: 11px;
|
|
213
|
+
font-weight: 600;
|
|
214
|
+
padding: 4px 10px;
|
|
215
|
+
border-radius: 999px;
|
|
216
|
+
background: var(--accent-soft);
|
|
217
|
+
color: var(--accent);
|
|
218
|
+
border: 1px solid #bae6fd;
|
|
219
|
+
}
|
|
220
|
+
.pill.emerald {
|
|
221
|
+
background: var(--emerald-soft);
|
|
222
|
+
color: var(--emerald);
|
|
223
|
+
border-color: #a7f3d0;
|
|
224
|
+
}
|
|
225
|
+
h1 {
|
|
226
|
+
font-size: clamp(26px, 4vw, 38px);
|
|
227
|
+
line-height: 1.18;
|
|
228
|
+
letter-spacing: -0.03em;
|
|
229
|
+
margin: 0 0 14px;
|
|
230
|
+
}
|
|
231
|
+
.lead {
|
|
232
|
+
font-size: 16px;
|
|
233
|
+
color: var(--muted);
|
|
234
|
+
max-width: 760px;
|
|
235
|
+
margin: 0 0 28px;
|
|
236
|
+
}
|
|
237
|
+
.grid-2 {
|
|
238
|
+
display: grid;
|
|
239
|
+
grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
|
|
240
|
+
gap: 18px;
|
|
241
|
+
margin-bottom: 28px;
|
|
242
|
+
}
|
|
243
|
+
.card {
|
|
244
|
+
background: var(--surface);
|
|
245
|
+
border: 1px solid var(--border);
|
|
246
|
+
border-radius: 12px;
|
|
247
|
+
padding: 22px;
|
|
248
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
|
|
249
|
+
}
|
|
250
|
+
.card h2, .card h3 {
|
|
251
|
+
margin-top: 0;
|
|
252
|
+
letter-spacing: -0.02em;
|
|
253
|
+
}
|
|
254
|
+
.code-box {
|
|
255
|
+
background: #09090b;
|
|
256
|
+
color: #f4f4f5;
|
|
257
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
258
|
+
font-size: 12.5px;
|
|
259
|
+
padding: 16px;
|
|
260
|
+
border-radius: 10px;
|
|
261
|
+
overflow-x: auto;
|
|
262
|
+
line-height: 1.65;
|
|
263
|
+
margin: 14px 0;
|
|
264
|
+
}
|
|
265
|
+
.code-box .comment { color: #71717a; }
|
|
266
|
+
.code-box .cmd { color: #38bdf8; }
|
|
267
|
+
.code-box .ok { color: #34d399; }
|
|
268
|
+
table {
|
|
269
|
+
width: 100%;
|
|
270
|
+
border-collapse: collapse;
|
|
271
|
+
font-size: 13.5px;
|
|
272
|
+
margin: 12px 0;
|
|
273
|
+
}
|
|
274
|
+
th, td {
|
|
275
|
+
text-align: left;
|
|
276
|
+
padding: 11px 12px;
|
|
277
|
+
border-bottom: 1px solid var(--border);
|
|
278
|
+
}
|
|
279
|
+
th {
|
|
280
|
+
font-size: 11.5px;
|
|
281
|
+
text-transform: uppercase;
|
|
282
|
+
letter-spacing: 0.04em;
|
|
283
|
+
color: var(--subtle);
|
|
284
|
+
background: #f4f4f5;
|
|
285
|
+
}
|
|
286
|
+
.calc-row {
|
|
287
|
+
display: flex;
|
|
288
|
+
align-items: center;
|
|
289
|
+
justify-content: space-between;
|
|
290
|
+
gap: 12px;
|
|
291
|
+
margin: 12px 0;
|
|
292
|
+
font-size: 13.5px;
|
|
293
|
+
}
|
|
294
|
+
.calc-output {
|
|
295
|
+
font-size: 24px;
|
|
296
|
+
font-weight: 700;
|
|
297
|
+
color: var(--emerald);
|
|
298
|
+
letter-spacing: -0.02em;
|
|
299
|
+
}
|
|
300
|
+
.cluster-grid {
|
|
301
|
+
display: grid;
|
|
302
|
+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
|
303
|
+
gap: 10px;
|
|
304
|
+
margin-top: 14px;
|
|
305
|
+
}
|
|
306
|
+
.cluster-link {
|
|
307
|
+
display: block;
|
|
308
|
+
padding: 11px 14px;
|
|
309
|
+
border-radius: 8px;
|
|
310
|
+
border: 1px solid var(--border);
|
|
311
|
+
background: var(--surface);
|
|
312
|
+
color: var(--text);
|
|
313
|
+
text-decoration: none;
|
|
314
|
+
font-size: 13px;
|
|
315
|
+
font-weight: 500;
|
|
316
|
+
transition: border-color 0.15s ease;
|
|
317
|
+
}
|
|
318
|
+
.cluster-link:hover {
|
|
319
|
+
border-color: var(--accent);
|
|
320
|
+
color: var(--accent);
|
|
321
|
+
}
|
|
322
|
+
.cluster-meta {
|
|
323
|
+
display: block;
|
|
324
|
+
font-size: 11px;
|
|
325
|
+
color: var(--subtle);
|
|
326
|
+
margin-top: 2px;
|
|
327
|
+
}
|
|
328
|
+
</style>
|
|
329
|
+
</head>
|
|
330
|
+
<body>
|
|
331
|
+
<div class="container">
|
|
332
|
+
<header class="topbar">
|
|
333
|
+
<a href="/" class="brand">
|
|
334
|
+
<svg width="24" height="24" viewBox="0 0 32 32" fill="none">
|
|
335
|
+
<rect width="32" height="32" rx="8" fill="#09090B"/>
|
|
336
|
+
<rect x="6" y="7" width="8" height="8" rx="2" stroke="#FFFFFF" stroke-width="2.2"/>
|
|
337
|
+
<rect x="6" y="17" width="8" height="8" rx="2" stroke="#FFFFFF" stroke-width="2.2" opacity="0.5"/>
|
|
338
|
+
<path d="M18 11H26M26 11L22.8 7.8M26 11L22.8 14.2" stroke="#38BDF8" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
339
|
+
<circle cx="22" cy="21" r="2.8" fill="#FFFFFF"/>
|
|
340
|
+
</svg>
|
|
341
|
+
<span>${escapeHtml(cleanName)}</span>
|
|
342
|
+
<span class="brand-badge">git paid</span>
|
|
343
|
+
</a>
|
|
344
|
+
<div style="display:flex;gap:10px;align-items:center;">
|
|
345
|
+
<a href="/?tab=agent" class="brand-badge" style="text-decoration:none;padding:6px 11px;">Stateful MCP v2.1</a>
|
|
346
|
+
<a href="/?utm_source=pseo&utm_campaign=${encodeURIComponent(page.id || "guide")}" class="cta-btn">
|
|
347
|
+
<span>Run Live Domain Audit</span>
|
|
348
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
|
|
349
|
+
</a>
|
|
350
|
+
</div>
|
|
351
|
+
</header>
|
|
352
|
+
|
|
353
|
+
<main>
|
|
354
|
+
<div class="pill-row">
|
|
355
|
+
<span class="pill">${escapeHtml(categoryLabel)}</span>
|
|
356
|
+
<span class="pill emerald">Intent: ${escapeHtml(page.intent || "High Intent")}</span>
|
|
357
|
+
<span class="pill">Search Volume: ${escapeHtml(page.volume || "1,400/mo")} (${escapeHtml(page.kd || "KD 11")})</span>
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
<h1>${escapeHtml(title)}</h1>
|
|
361
|
+
<p class="lead">
|
|
362
|
+
Shipping code with <code>git push</code> is only half the battle. Here is the deterministic engineering blueprint for <strong>${escapeHtml(page.keyword)}</strong>—combining 25 programmatic SEO routes, an autonomous <code>@postbuild.dev</code> verification inbox, and 85-directory dispatch via <code>npx git-paid</code>.
|
|
363
|
+
</p>
|
|
364
|
+
|
|
365
|
+
<div class="grid-2">
|
|
366
|
+
<section class="card">
|
|
367
|
+
<h3>1-Command CLI & Stateful MCP Execution</h3>
|
|
368
|
+
<p style="font-size:13.5px;color:var(--muted);margin-top:4px;">
|
|
369
|
+
Run directly from your project root after deploying to Vercel, Railway, or Fly.io, or attach as an MCP server inside Claude Code, Cursor, or Gemini.
|
|
370
|
+
</p>
|
|
371
|
+
<div class="code-box">
|
|
372
|
+
<div><span class="comment"># 1. Audit your live URL & write 25 pSEO routes + llms.txt</span></div>
|
|
373
|
+
<div><span class="cmd">$ npx git-paid fix https://${escapeHtml(domain)}</span></div>
|
|
374
|
+
<div style="margin-top:8px;"><span class="comment"># 2. Dispatch across 85 curated directories with OCC safety</span></div>
|
|
375
|
+
<div><span class="cmd">$ npx git-paid submit https://${escapeHtml(domain)} --limit 10</span></div>
|
|
376
|
+
<div style="margin-top:8px;"><span class="comment"># 3. Auto-verify inbound @postbuild.dev OTPs & links</span></div>
|
|
377
|
+
<div><span class="ok">✔ Verified 100% of inbound directory confirmation links</span></div>
|
|
378
|
+
</div>
|
|
379
|
+
<a href="/?domain=${encodeURIComponent(domain)}" class="cta-btn" style="width:100%;justify-content:center;margin-top:10px;">
|
|
380
|
+
Launch Interactive Workspace for ${escapeHtml(domain)}
|
|
381
|
+
</a>
|
|
382
|
+
</section>
|
|
383
|
+
|
|
384
|
+
<section class="card">
|
|
385
|
+
<h3>Interactive Launch ROI & Time Saved Estimator</h3>
|
|
386
|
+
<p style="font-size:13.5px;color:var(--muted);margin-top:4px;">
|
|
387
|
+
Adjust your monthly launch cadence to compare manual directory & pSEO setup against <code>git paid</code> automation.
|
|
388
|
+
</p>
|
|
389
|
+
<div class="calc-row">
|
|
390
|
+
<label for="projectsRange"><strong>Projects / Features Launched per Year:</strong></label>
|
|
391
|
+
<span id="projectsVal" style="font-weight:700;">4 launches</span>
|
|
392
|
+
</div>
|
|
393
|
+
<input id="projectsRange" type="range" min="1" max="20" value="4" style="width:100%;accent-color:#09090b;" oninput="updateRoi(this.value)" />
|
|
394
|
+
<div class="calc-row" style="margin-top:16px;padding-top:12px;border-top:1px solid var(--border);">
|
|
395
|
+
<span>Engineering & Founder Hours Saved:</span>
|
|
396
|
+
<span id="hoursSaved" class="calc-output">112 hrs</span>
|
|
397
|
+
</div>
|
|
398
|
+
<div class="calc-row">
|
|
399
|
+
<span>Indexed Programmatic SEO Landing Pages:</span>
|
|
400
|
+
<span id="pagesBuilt" style="font-weight:700;font-size:16px;">100 routes</span>
|
|
401
|
+
</div>
|
|
402
|
+
<div class="calc-row">
|
|
403
|
+
<span>High-DR Backlink Submissions Dispatched:</span>
|
|
404
|
+
<span id="dirsDispatched" style="font-weight:700;font-size:16px;">340 listings</span>
|
|
405
|
+
</div>
|
|
406
|
+
</section>
|
|
407
|
+
</div>
|
|
408
|
+
|
|
409
|
+
<section class="card" style="margin-bottom:28px;">
|
|
410
|
+
<h2>Manual Post-Build Workflow vs. ${escapeHtml(cleanName)} (<code>git paid</code>)</h2>
|
|
411
|
+
<table>
|
|
412
|
+
<thead>
|
|
413
|
+
<tr>
|
|
414
|
+
<th>Post-Build Capability</th>
|
|
415
|
+
<th>Manual Workflow / Spreadsheets</th>
|
|
416
|
+
<th>${escapeHtml(cleanName)} Autonomous Engine</th>
|
|
417
|
+
</tr>
|
|
418
|
+
</thead>
|
|
419
|
+
<tbody>
|
|
420
|
+
<tr>
|
|
421
|
+
<td><strong>85-Directory Submission & UTM Tagging</strong></td>
|
|
422
|
+
<td>14+ hours of repetitive copy-pasting & form filling</td>
|
|
423
|
+
<td>Automated pre-filled & API dispatch via <code>git paid submit</code></td>
|
|
424
|
+
</tr>
|
|
425
|
+
<tr>
|
|
426
|
+
<td><strong>Directory Verification Emails & OTPs</strong></td>
|
|
427
|
+
<td>Clutters personal founder inbox with 85+ confirmation emails</td>
|
|
428
|
+
<td>Dedicated <code>*@postbuild.dev</code> Resend inbox + Agent Auto-Verifier</td>
|
|
429
|
+
</tr>
|
|
430
|
+
<tr>
|
|
431
|
+
<td><strong>Programmatic SEO Architecture</strong></td>
|
|
432
|
+
<td>Manual keyword research & hand-coded static pages</td>
|
|
433
|
+
<td>25 pre-rendered routes + <code>sitemap.xml</code> + <code>llms.txt</code> in 1 command</td>
|
|
434
|
+
</tr>
|
|
435
|
+
<tr>
|
|
436
|
+
<td><strong>AI Agent MCP Context Efficiency</strong></td>
|
|
437
|
+
<td>Stateless JSON re-serialization (280 KB+ across 5 turns)</td>
|
|
438
|
+
<td>Stateful watermark deltas (<code>unchanged@vN</code> — <strong>-84% token overhead</strong>)</td>
|
|
439
|
+
</tr>
|
|
440
|
+
</tbody>
|
|
441
|
+
</table>
|
|
442
|
+
</section>
|
|
443
|
+
|
|
444
|
+
<section class="card">
|
|
445
|
+
<h3>Explore All 25 Programmatic SEO Blueprints</h3>
|
|
446
|
+
<p style="font-size:13px;color:var(--muted);margin-top:0;">
|
|
447
|
+
Every route below is pre-indexed in <code>sitemap.xml</code> and <code>llms.txt</code> for Google, ChatGPT Search (<code>OAI-SearchBot</code>), Perplexity, and Claude.
|
|
448
|
+
</p>
|
|
449
|
+
<div class="cluster-grid">
|
|
450
|
+
${relatedPages
|
|
451
|
+
.map((rp) => {
|
|
452
|
+
const meta = humanizeSlug(rp.path, cleanName);
|
|
453
|
+
return `<a class="cluster-link" href="${escapeHtml(rp.path)}">
|
|
454
|
+
<span>${escapeHtml(meta.title)}</span>
|
|
455
|
+
<span class="cluster-meta">${escapeHtml(rp.keyword)} • ${escapeHtml(rp.volume)}</span>
|
|
456
|
+
</a>`;
|
|
457
|
+
})
|
|
458
|
+
.join("\n ")}
|
|
459
|
+
</div>
|
|
460
|
+
</section>
|
|
461
|
+
</main>
|
|
462
|
+
</div>
|
|
463
|
+
<script>
|
|
464
|
+
function updateRoi(val) {
|
|
465
|
+
var n = parseInt(val, 10) || 1;
|
|
466
|
+
document.getElementById('projectsVal').textContent = n + (n === 1 ? ' launch' : ' launches');
|
|
467
|
+
document.getElementById('hoursSaved').textContent = (n * 28) + ' hrs';
|
|
468
|
+
document.getElementById('pagesBuilt').textContent = (n * 25) + ' routes';
|
|
469
|
+
document.getElementById('dirsDispatched').textContent = (n * 85) + ' listings';
|
|
470
|
+
}
|
|
471
|
+
</script>
|
|
472
|
+
</body>
|
|
473
|
+
</html>`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Writes all 25 Programmatic SEO HTML files into targetBaseDir so cleanUrls (/use-cases/...) resolve with 200 OK.
|
|
478
|
+
*/
|
|
479
|
+
export function writePseoHtmlFiles(pseoPages = [], targetBaseDir, options = {}) {
|
|
480
|
+
const written = [];
|
|
481
|
+
for (const page of pseoPages) {
|
|
482
|
+
const cleanRel = String(page.path || "").replace(/^\/+/, "");
|
|
483
|
+
if (!cleanRel) continue;
|
|
484
|
+
const outFile = path.join(targetBaseDir, `${cleanRel}.html`);
|
|
485
|
+
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
486
|
+
const html = renderSinglePseoPage(page, pseoPages, options);
|
|
487
|
+
fs.writeFileSync(outFile, html, "utf8");
|
|
488
|
+
written.push(outFile);
|
|
489
|
+
}
|
|
490
|
+
return written;
|
|
491
|
+
}
|