git-paid 0.0.0-stage → 2.1.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/README.md +114 -2
- 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 +41 -4
- package/server.js +252 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Complete 85-Directory Database for Postbuild (postbuild.dev)
|
|
2
|
+
// Curated startup, AI, developer, indie SaaS, and software discovery directories.
|
|
3
|
+
|
|
4
|
+
export const DIRECTORIES = [
|
|
5
|
+
// Tier 1: Major Launch Boards & Communities (1-15)
|
|
6
|
+
{ id: "dir-01", name: "Product Hunt", url: "https://www.producthunt.com/posts/new", dr: 91, category: "Launch Board", authType: "OAuth / Magic Link", autoSubmit: true },
|
|
7
|
+
{ id: "dir-02", name: "Hacker News (Show HN)", url: "https://news.ycombinator.com/submit", dr: 92, category: "Developer Community", authType: "Account Session", autoSubmit: true },
|
|
8
|
+
{ id: "dir-03", name: "AlternativeTo", url: "https://alternativeto.net/add-application/", dr: 86, category: "Software Discovery", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
9
|
+
{ id: "dir-04", name: "There's An AI For That", url: "https://theresanaiforthat.com/submit/", dr: 82, category: "AI Directory", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
10
|
+
{ id: "dir-05", name: "Indie Hackers Products", url: "https://www.indiehackers.com/products", dr: 81, category: "Indie SaaS", authType: "Email Link", autoSubmit: true },
|
|
11
|
+
{ id: "dir-06", name: "Futurepedia", url: "https://www.futurepedia.io/submit-tool", dr: 79, category: "AI Directory", authType: "Email Verification", autoSubmit: true },
|
|
12
|
+
{ id: "dir-07", name: "SaaSHub", url: "https://www.saashub.com/submit", dr: 77, category: "Software Directory", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
13
|
+
{ id: "dir-08", name: "BetaList", url: "https://betalist.com/submit", dr: 76, category: "Early Adopters", authType: "Email Verification", autoSubmit: true },
|
|
14
|
+
{ id: "dir-09", name: "FutureTools.io", url: "https://www.futuretools.io/submit-a-tool", dr: 75, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
15
|
+
{ id: "dir-10", name: "Toolify.ai", url: "https://www.toolify.ai/submit", dr: 74, category: "AI Directory", authType: "Direct Form + Email", autoSubmit: true },
|
|
16
|
+
{ id: "dir-11", name: "G2 Software", url: "https://www.g2.com/products/new", dr: 90, category: "B2B Software", authType: "Work Email (@postbuild.dev)", autoSubmit: true },
|
|
17
|
+
{ id: "dir-12", name: "Crozdesk", url: "https://crozdesk.com/vendors", dr: 73, category: "B2B SaaS", authType: "Email Verification", autoSubmit: true },
|
|
18
|
+
{ id: "dir-13", name: "SourceForge", url: "https://sourceforge.net/create/", dr: 91, category: "Developer Tools", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
19
|
+
{ id: "dir-14", name: "Slant.co", url: "https://www.slant.co", dr: 80, category: "Comparison Engine", authType: "Account Session", autoSubmit: true },
|
|
20
|
+
{ id: "dir-15", name: "StackShare", url: "https://stackshare.io/submit", dr: 82, category: "Developer Stack", authType: "GitHub / Email", autoSubmit: true },
|
|
21
|
+
|
|
22
|
+
// Tier 2: Developer & Open-Source Directories (16-30)
|
|
23
|
+
{ id: "dir-16", name: "DevHunt", url: "https://devhunt.org/login", dr: 68, category: "Developer Tools", authType: "GitHub / Email", autoSubmit: true },
|
|
24
|
+
{ id: "dir-17", name: "OpenAlternative", url: "https://openalternative.co/submit", dr: 66, category: "Open Source", authType: "Direct Form", autoSubmit: true },
|
|
25
|
+
{ id: "dir-18", name: "Console.dev", url: "https://console.dev/submit", dr: 69, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
26
|
+
{ id: "dir-19", name: "LibHunt", url: "https://www.libhunt.com", dr: 72, category: "Developer Libraries", authType: "GitHub Link", autoSubmit: true },
|
|
27
|
+
{ id: "dir-20", name: "Awesome Lists Index", url: "https://awesomelists.top", dr: 61, category: "Open Source", authType: "PR / Form", autoSubmit: true },
|
|
28
|
+
{ id: "dir-21", name: "FindDevTools", url: "https://finddevtools.com/submit", dr: 54, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
29
|
+
{ id: "dir-22", name: "DevPages", url: "https://www.devpages.io/submit", dr: 52, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
30
|
+
{ id: "dir-23", name: "Tooling.one", url: "https://tooling.one/submit", dr: 49, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
31
|
+
{ id: "dir-24", name: "Daily.dev Picks", url: "https://daily.dev", dr: 76, category: "Developer Feed", authType: "Email Link", autoSubmit: true },
|
|
32
|
+
{ id: "dir-25", name: "CodeGems", url: "https://codegems.io", dr: 48, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
33
|
+
{ id: "dir-26", name: "HelloGitHub", url: "https://hellogithub.com", dr: 64, category: "Open Source", authType: "Direct Form", autoSubmit: true },
|
|
34
|
+
{ id: "dir-27", name: "RepoTrends", url: "https://repotrends.com", dr: 51, category: "Developer Tools", authType: "Direct Form", autoSubmit: true },
|
|
35
|
+
{ id: "dir-28", name: "Selfh.st", url: "https://selfh.st/submit", dr: 62, category: "Self-Hosted / Dev", authType: "Direct Form", autoSubmit: true },
|
|
36
|
+
{ id: "dir-29", name: "CLI.club", url: "https://cli.club", dr: 46, category: "CLI Tools", authType: "Direct Form", autoSubmit: true },
|
|
37
|
+
{ id: "dir-30", name: "TerminalTroves", url: "https://terminaltrove.com/submit/", dr: 58, category: "CLI & Terminal", authType: "Direct Form", autoSubmit: true },
|
|
38
|
+
|
|
39
|
+
// Tier 3: Indie Launch & Maker Platforms (31-50)
|
|
40
|
+
{ id: "dir-31", name: "Uneed.best", url: "https://www.uneed.best/submit-a-tool", dr: 64, category: "Indie Launch", authType: "Magic Link (@postbuild.dev)", autoSubmit: true },
|
|
41
|
+
{ id: "dir-32", name: "MicroLaunch", url: "https://microlaunch.net/submit", dr: 59, category: "Indie Launch", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
42
|
+
{ id: "dir-33", name: "TinyLaunch", url: "https://tinylaunch.com/submit", dr: 54, category: "Indie Launch", authType: "Direct Form + Email", autoSubmit: true },
|
|
43
|
+
{ id: "dir-34", name: "Launching Next", url: "https://www.launchingnext.com/submit/", dr: 67, category: "Startup Directory", authType: "Direct Form", autoSubmit: true },
|
|
44
|
+
{ id: "dir-35", name: "SideProjectors", url: "https://www.sideprojectors.com/project/submit", dr: 62, category: "Side Projects", authType: "Email Verification", autoSubmit: true },
|
|
45
|
+
{ id: "dir-36", name: "StartupBase", url: "https://startupbase.io/submit", dr: 61, category: "Startup Directory", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
46
|
+
{ id: "dir-37", name: "Peerlist Spotlight", url: "https://peerlist.io/projects", dr: 74, category: "Maker Network", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
47
|
+
{ id: "dir-38", name: "1000.tools", url: "https://1000.tools/submit", dr: 57, category: "Indie Tools", authType: "Direct Form", autoSubmit: true },
|
|
48
|
+
{ id: "dir-39", name: "Fazier", url: "https://fazier.com/launch", dr: 56, category: "Indie Launch", authType: "Magic Link (@postbuild.dev)", autoSubmit: true },
|
|
49
|
+
{ id: "dir-40", name: "Huzzler", url: "https://huzzler.so/products", dr: 55, category: "Indie Founders", authType: "Email Verification", autoSubmit: true },
|
|
50
|
+
{ id: "dir-41", name: "IndiePage", url: "https://indiepa.ge", dr: 63, category: "Maker Portfolio", authType: "Magic Link (@postbuild.dev)", autoSubmit: true },
|
|
51
|
+
{ id: "dir-42", name: "BetaPage", url: "https://betapage.co/submit-startup", dr: 68, category: "Startup Launch", authType: "Email Verification", autoSubmit: true },
|
|
52
|
+
{ id: "dir-43", name: "StartupBuffer", url: "https://startupbuffer.com/site/submit", dr: 60, category: "Startup Directory", authType: "Direct Form", autoSubmit: true },
|
|
53
|
+
{ id: "dir-44", name: "StartupStash", url: "https://startupstash.com/add-listing/", dr: 72, category: "Startup Resources", authType: "Direct Form + Email", autoSubmit: true },
|
|
54
|
+
{ id: "dir-45", name: "KillerStartups", url: "https://www.killerstartups.com/submit-startup", dr: 71, category: "Startup Reviews", authType: "Direct Form", autoSubmit: true },
|
|
55
|
+
{ id: "dir-46", name: "CrazyAboutStartups", url: "https://www.crazyaboutstartups.com/submit-startup/", dr: 55, category: "Startup Directory", authType: "Direct Form", autoSubmit: true },
|
|
56
|
+
{ id: "dir-47", name: "Startups.fyi", url: "https://www.startups.fyi/submit", dr: 58, category: "Startup Discovery", authType: "Direct Form", autoSubmit: true },
|
|
57
|
+
{ id: "dir-48", name: "NoCodeList", url: "https://nocodelist.co/submit", dr: 57, category: "Modern Software", authType: "Direct Form", autoSubmit: true },
|
|
58
|
+
{ id: "dir-49", name: "Makerlog Products", url: "https://getmakerlog.com", dr: 60, category: "Maker Community", authType: "Email Verification", autoSubmit: true },
|
|
59
|
+
{ id: "dir-50", name: "wip.co Products", url: "https://wip.co", dr: 63, category: "Maker Community", authType: "Account Session", autoSubmit: true },
|
|
60
|
+
|
|
61
|
+
// Tier 4: AI & Automation Directories (51-70)
|
|
62
|
+
{ id: "dir-51", name: "TopAI.tools", url: "https://topai.tools/submit", dr: 69, category: "AI Directory", authType: "Email Verification", autoSubmit: true },
|
|
63
|
+
{ id: "dir-52", name: "AI Scout", url: "https://aiscout.net/submit-listing/", dr: 58, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
64
|
+
{ id: "dir-53", name: "Easy With AI", url: "https://easywithai.com/submit-tool/", dr: 66, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
65
|
+
{ id: "dir-54", name: "AI Tool Hunt", url: "https://www.aitoolhunt.com/submit", dr: 61, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
66
|
+
{ id: "dir-55", name: "Insidr.ai", url: "https://www.insidr.ai/submit-tools/", dr: 65, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
67
|
+
{ id: "dir-56", name: "AI Valley", url: "https://aivalley.ai/submit-tool/", dr: 57, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
68
|
+
{ id: "dir-57", name: "AllThingsAI", url: "https://allthingsai.com/submit", dr: 64, category: "AI Directory", authType: "Email Verification", autoSubmit: true },
|
|
69
|
+
{ id: "dir-58", name: "AIDir.cc", url: "https://aidir.cc/submit", dr: 49, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
70
|
+
{ id: "dir-59", name: "OpenTools.ai", url: "https://opentools.ai/submit-a-tool", dr: 67, category: "AI Directory", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
71
|
+
{ id: "dir-60", name: "AIxploria", url: "https://www.aixploria.com/en/add-ai/", dr: 71, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
72
|
+
{ id: "dir-61", name: "SaaS AI Tools", url: "https://saasaitools.com/submit/", dr: 59, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
73
|
+
{ id: "dir-62", name: "GPTE.ai", url: "https://gpte.ai/submit-a-tool/", dr: 62, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
74
|
+
{ id: "dir-63", name: "AI Center", url: "https://aicenter.ai/submit", dr: 53, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
75
|
+
{ id: "dir-64", name: "AI Tools Directory", url: "https://aitoolsdirectory.com/submit-tool", dr: 63, category: "AI Directory", authType: "Direct Form + Email", autoSubmit: true },
|
|
76
|
+
{ id: "dir-65", name: "NextGenTools", url: "https://www.nxgntools.com/submit", dr: 55, category: "AI & SaaS", authType: "Magic Link (@postbuild.dev)", autoSubmit: true },
|
|
77
|
+
{ id: "dir-66", name: "BasedTools", url: "https://www.basedtools.ai/submit", dr: 54, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
78
|
+
{ id: "dir-67", name: "Tap4 AI", url: "https://tap4.ai/submit", dr: 58, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
79
|
+
{ id: "dir-68", name: "WaildWorld AI", url: "https://waildworld.com/submit", dr: 48, category: "AI Directory", authType: "Direct Form", autoSubmit: true },
|
|
80
|
+
{ id: "dir-69", name: "AgentLocker", url: "https://agentlocker.ai/submit", dr: 51, category: "AI Agents", authType: "Direct Form", autoSubmit: true },
|
|
81
|
+
{ id: "dir-70", name: "MCP.so Directory", url: "https://mcp.so/submit", dr: 64, category: "MCP & Agents", authType: "GitHub / Form", autoSubmit: true },
|
|
82
|
+
|
|
83
|
+
// Tier 5: SaaS, Growth & Niche Directories (71-85)
|
|
84
|
+
{ id: "dir-71", name: "SaaSWorthy", url: "https://www.saasworthy.com/offerings", dr: 74, category: "SaaS Directory", authType: "Work Email (@postbuild.dev)", autoSubmit: true },
|
|
85
|
+
{ id: "dir-72", name: "GetApp / Capterra", url: "https://www.capterra.com/vendors/sign-up", dr: 90, category: "B2B Software", authType: "Work Email (@postbuild.dev)", autoSubmit: true },
|
|
86
|
+
{ id: "dir-73", name: "SoftwareSuggest", url: "https://www.softwaresuggest.com/vendors", dr: 76, category: "SaaS Directory", authType: "Email Verification", autoSubmit: true },
|
|
87
|
+
{ id: "dir-74", name: "GoodFirms", url: "https://www.goodfirms.co/get-listed", dr: 84, category: "Software Directory", authType: "Email Verification", autoSubmit: true },
|
|
88
|
+
{ id: "dir-75", name: "TrustRadius", url: "https://www.trustradius.com/vendor", dr: 85, category: "B2B Software", authType: "Work Email (@postbuild.dev)", autoSubmit: true },
|
|
89
|
+
{ id: "dir-76", name: "Serchen", url: "https://www.serchen.com/get-listed/", dr: 68, category: "Cloud & SaaS", authType: "Email Verification", autoSubmit: true },
|
|
90
|
+
{ id: "dir-77", name: "Cloudswave", url: "https://www.cloudswave.com", dr: 61, category: "Cloud SaaS", authType: "Direct Form", autoSubmit: true },
|
|
91
|
+
{ id: "dir-78", name: "Feedough Startups", url: "https://www.feedough.com/submit-your-startup/", dr: 69, category: "Startup Media", authType: "Direct Form", autoSubmit: true },
|
|
92
|
+
{ id: "dir-79", name: "EU-Startups Directory", url: "https://www.eu-startups.com/directory/", dr: 78, category: "Startup Directory", authType: "Email Verification", autoSubmit: true },
|
|
93
|
+
{ id: "dir-80", name: "F6S Startup Network", url: "https://www.f6s.com", dr: 83, category: "Founder Network", authType: "OTP (@postbuild.dev)", autoSubmit: true },
|
|
94
|
+
{ id: "dir-81", name: "Gust Startups", url: "https://gust.com", dr: 80, category: "Startup Platform", authType: "Email Verification", autoSubmit: true },
|
|
95
|
+
{ id: "dir-82", name: "IndieDeals", url: "https://indiedeals.co/submit", dr: 50, category: "Deals & Launch", authType: "Direct Form", autoSubmit: true },
|
|
96
|
+
{ id: "dir-83", name: "PitchWall", url: "https://pitchwall.co", dr: 65, category: "Product Pitch", authType: "Email Verification", autoSubmit: true },
|
|
97
|
+
{ id: "dir-84", name: "Land-book", url: "https://land-book.com/submit", dr: 73, category: "Landing Design", authType: "Direct Form", autoSubmit: true },
|
|
98
|
+
{ id: "dir-85", name: "OnePageLove", url: "https://onepagelove.com/submit", dr: 79, category: "Landing Showcase", authType: "Direct Form", autoSubmit: true }
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
export function buildPrefilledDirectoryUrl(dir, launchKit) {
|
|
102
|
+
try {
|
|
103
|
+
const u = new URL(dir.url);
|
|
104
|
+
const utmTarget = launchKit?.utmUrl || launchKit?.targetUrl || "https://postbuild.dev";
|
|
105
|
+
const name = launchKit?.productName || "Postbuild";
|
|
106
|
+
const tagline = launchKit?.tagline || "Ship code, automate SEO and directory dispatch";
|
|
107
|
+
|
|
108
|
+
if (dir.url.includes("news.ycombinator.com/submit")) {
|
|
109
|
+
u.searchParams.set("u", utmTarget);
|
|
110
|
+
u.searchParams.set("t", `Show HN: ${name} – ${tagline}`);
|
|
111
|
+
return u.toString();
|
|
112
|
+
}
|
|
113
|
+
u.searchParams.set("url", utmTarget);
|
|
114
|
+
u.searchParams.set("name", name);
|
|
115
|
+
u.searchParams.set("tagline", tagline);
|
|
116
|
+
if (launchKit?.makerEmail) {
|
|
117
|
+
u.searchParams.set("email", launchKit.makerEmail);
|
|
118
|
+
}
|
|
119
|
+
return u.toString();
|
|
120
|
+
} catch {
|
|
121
|
+
return dir.url;
|
|
122
|
+
}
|
|
123
|
+
}
|
package/lib/engine.js
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
// Core Autonomous Engine for Postbuild (postbuild.dev)
|
|
2
|
+
// Handles live URL auditing, Launch Kit synthesis, 25-route Programmatic SEO generation,
|
|
3
|
+
// 85-directory dispatch preparation, and Live Buyer Intent Radar.
|
|
4
|
+
|
|
5
|
+
import { DIRECTORIES, buildPrefilledDirectoryUrl } from "./directories.js";
|
|
6
|
+
|
|
7
|
+
export { DIRECTORIES };
|
|
8
|
+
|
|
9
|
+
function extractTag(html, regex) {
|
|
10
|
+
const m = html.match(regex);
|
|
11
|
+
return m && m[1] ? m[1].replace(/\s+/g, " ").trim() : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function extractAllTags(html, regex, limit = 6) {
|
|
15
|
+
const results = [];
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = regex.exec(html)) !== null && results.length < limit) {
|
|
18
|
+
const clean = match[1].replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
19
|
+
if (clean && clean.length > 3 && !results.includes(clean)) {
|
|
20
|
+
results.push(clean);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return results;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function inferCategories(text) {
|
|
27
|
+
const lower = (text || "").toLowerCase();
|
|
28
|
+
const cats = [];
|
|
29
|
+
if (/cli|git|sdk|api|developer|code|terminal|repo|deploy/.test(lower)) cats.push("Developer Tools");
|
|
30
|
+
if (/ai|llm|agent|gpt|claude|model|prompt|automation/.test(lower)) cats.push("AI & Automation");
|
|
31
|
+
if (/seo|marketing|directory|launch|growth|leads|traffic/.test(lower)) cats.push("Marketing & SEO");
|
|
32
|
+
if (/stripe|pay|revenue|billing|invoice|saas|pricing/.test(lower)) cats.push("SaaS & Monetization");
|
|
33
|
+
if (cats.length === 0) cats.push("SaaS", "Productivity", "Software");
|
|
34
|
+
return cats.slice(0, 3);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function scanTargetUrl(rawInput) {
|
|
38
|
+
let targetUrl = (rawInput || "https://postbuild.dev").trim();
|
|
39
|
+
if (!/^https?:\/\//i.test(targetUrl)) {
|
|
40
|
+
targetUrl = "https://" + targetUrl;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let parsedUrl;
|
|
44
|
+
try {
|
|
45
|
+
parsedUrl = new URL(targetUrl);
|
|
46
|
+
} catch {
|
|
47
|
+
parsedUrl = new URL("https://postbuild.dev");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const domain = parsedUrl.hostname.replace(/^www\./, "");
|
|
51
|
+
const slug = domain.split(".")[0].toLowerCase().replace(/[^a-z0-9-]/g, "") || "app";
|
|
52
|
+
const botEmail = `${slug}-bot@postbuild.dev`;
|
|
53
|
+
|
|
54
|
+
let html = "";
|
|
55
|
+
let reachable = false;
|
|
56
|
+
let robotsText = "";
|
|
57
|
+
let hasRobots = false;
|
|
58
|
+
let sitemapText = "";
|
|
59
|
+
let hasSitemap = false;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
const timer = setTimeout(() => controller.abort(), 5500);
|
|
64
|
+
const res = await fetch(parsedUrl.toString(), {
|
|
65
|
+
signal: controller.signal,
|
|
66
|
+
headers: { "User-Agent": "PostbuildBot/1.0 (+https://postbuild.dev)" }
|
|
67
|
+
});
|
|
68
|
+
clearTimeout(timer);
|
|
69
|
+
if (res.ok) {
|
|
70
|
+
html = await res.text();
|
|
71
|
+
reachable = true;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
reachable = false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const rRes = await fetch(`${parsedUrl.origin}/robots.txt`, { signal: AbortSignal.timeout(3000) });
|
|
79
|
+
if (rRes.ok) {
|
|
80
|
+
robotsText = await rRes.text();
|
|
81
|
+
hasRobots = robotsText.length > 5 && !/<html/i.test(robotsText);
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
hasRobots = false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const sRes = await fetch(`${parsedUrl.origin}/sitemap.xml`, { signal: AbortSignal.timeout(3000) });
|
|
89
|
+
if (sRes.ok) {
|
|
90
|
+
sitemapText = await sRes.text();
|
|
91
|
+
hasSitemap = /<urlset|<sitemapindex/i.test(sitemapText);
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
hasSitemap = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const rawTitle =
|
|
98
|
+
extractTag(html, /<title[^>]*>([^<]+)<\/title>/i) ||
|
|
99
|
+
`${slug.charAt(0).toUpperCase() + slug.slice(1)} — Modern Workflow & Automation Platform`;
|
|
100
|
+
|
|
101
|
+
const description =
|
|
102
|
+
extractTag(html, /<meta[^>]+name=["']description["'][^>]+content=["']([^"']+)["']/i) ||
|
|
103
|
+
extractTag(html, /<meta[^>]+content=["']([^"']+)["'][^>]+name=["']description["']/i) ||
|
|
104
|
+
extractTag(html, /<meta[^>]+property=["']og:description["'][^>]+content=["']([^"']+)["']/i) ||
|
|
105
|
+
"";
|
|
106
|
+
|
|
107
|
+
const ogImage =
|
|
108
|
+
extractTag(html, /<meta[^>]+property=["']og:image["'][^>]+content=["']([^"']+)["']/i) ||
|
|
109
|
+
extractTag(html, /<meta[^>]+content=["']([^"']+)["'][^>]+property=["']og:image["']/i) ||
|
|
110
|
+
"";
|
|
111
|
+
|
|
112
|
+
const ogTitle =
|
|
113
|
+
extractTag(html, /<meta[^>]+property=["']og:title["'][^>]+content=["']([^"']+)["']/i) || "";
|
|
114
|
+
|
|
115
|
+
const h1List = extractAllTags(html, /<h1[^>]*>([\s\S]*?)<\/h1>/gi, 3);
|
|
116
|
+
const h2List = extractAllTags(html, /<h2[^>]*>([\s\S]*?)<\/h2>/gi, 6);
|
|
117
|
+
|
|
118
|
+
const hasJsonLd = /application\/ld\+json/i.test(html);
|
|
119
|
+
const hasCheckout = /polar\.sh|lemonsqueezy\.com|paddle\.com|buy\.stripe\.com|checkout\.stripe\.com|\/api\/checkout|Launch Pass/i.test(html);
|
|
120
|
+
const hasAnalytics = /posthog|plausible|gtag|googletagmanager|umami|vercel-insights|sola/i.test(html);
|
|
121
|
+
const hasDuplicateSnapshotMeta = (html.match(/manages 5 data types/gi) || []).length > 3;
|
|
122
|
+
|
|
123
|
+
const hasAiCrawlerRules = hasRobots && /OAI-SearchBot|PerplexityBot|ClaudeBot|GPTBot/i.test(robotsText);
|
|
124
|
+
const sitemapUrlCount = hasSitemap ? (sitemapText.match(/<loc>/gi) || []).length : 0;
|
|
125
|
+
const hasPseoSitemap = sitemapUrlCount >= 10;
|
|
126
|
+
|
|
127
|
+
const checks = [
|
|
128
|
+
{
|
|
129
|
+
id: "title",
|
|
130
|
+
label: "Title Tag & Keyword Hook",
|
|
131
|
+
passed: Boolean(rawTitle && rawTitle.length > 10),
|
|
132
|
+
detail: rawTitle || "Missing <title>"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "desc",
|
|
136
|
+
label: "Unique Route Meta Descriptions",
|
|
137
|
+
passed: Boolean(description && description.length >= 40 && !hasDuplicateSnapshotMeta),
|
|
138
|
+
detail: hasDuplicateSnapshotMeta
|
|
139
|
+
? "Detected multiple routes sharing identical boilerplate meta text (Auto-Fix Ready)"
|
|
140
|
+
: description
|
|
141
|
+
? `${description.slice(0, 82)}${description.length > 82 ? "..." : ""}`
|
|
142
|
+
: "Missing meta description tag"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "og",
|
|
146
|
+
label: "OpenGraph Social Preview Card",
|
|
147
|
+
passed: Boolean(ogImage || ogTitle),
|
|
148
|
+
detail: ogImage
|
|
149
|
+
? `Detected og:image (${ogImage.slice(0, 48)})`
|
|
150
|
+
: ogTitle
|
|
151
|
+
? `Detected og:title (${ogTitle.slice(0, 48)})`
|
|
152
|
+
: "Missing og:image preview card for X/LinkedIn/Product Hunt"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "jsonld",
|
|
156
|
+
label: "JSON-LD SoftwareApplication Schema",
|
|
157
|
+
passed: hasJsonLd,
|
|
158
|
+
detail: hasJsonLd ? "Structured SoftwareApplication schema active" : "Missing rich snippet schema for Google & AI Search"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "robots",
|
|
162
|
+
label: "AI Search Crawlers (ChatGPT / Perplexity)",
|
|
163
|
+
passed: hasAiCrawlerRules,
|
|
164
|
+
detail: hasAiCrawlerRules
|
|
165
|
+
? "Explicit OAI-SearchBot & PerplexityBot allow rules verified in robots.txt"
|
|
166
|
+
: hasRobots
|
|
167
|
+
? "robots.txt found, but missing explicit OAI-SearchBot & PerplexityBot rules"
|
|
168
|
+
: "Missing robots.txt with AI search crawler directives"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: "sitemap",
|
|
172
|
+
label: "Programmatic SEO Sitemap (25+ Routes)",
|
|
173
|
+
passed: hasPseoSitemap,
|
|
174
|
+
detail: hasSitemap
|
|
175
|
+
? `sitemap.xml active (${sitemapUrlCount} indexed routes — ${hasPseoSitemap ? "pSEO active" : "25 pSEO routes ready to add"})`
|
|
176
|
+
: "No sitemap.xml found — 25 high-intent pSEO routes ready to deploy"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: "paywall",
|
|
180
|
+
label: "Self-Serve Stripe / Polar Checkout Gate",
|
|
181
|
+
passed: hasCheckout,
|
|
182
|
+
detail: hasCheckout
|
|
183
|
+
? "Direct self-serve checkout gate detected on landing view"
|
|
184
|
+
: "No self-serve Stripe / Polar payment link detected on landing view"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
id: "analytics",
|
|
188
|
+
label: "Conversion Telemetry",
|
|
189
|
+
passed: hasAnalytics,
|
|
190
|
+
detail: hasAnalytics ? "Conversion telemetry active" : "No conversion pixel/analytics detected"
|
|
191
|
+
}
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
const passedCount = checks.filter(c => c.passed).length;
|
|
195
|
+
const readinessScore = Math.max(18, Math.round((passedCount / checks.length) * 100));
|
|
196
|
+
|
|
197
|
+
const titleParts = rawTitle.split(/\s*[|—–-]\s*/);
|
|
198
|
+
const cleanName = (titleParts[0] || slug).trim();
|
|
199
|
+
const extractedTagline =
|
|
200
|
+
(titleParts[1] && titleParts[1].length >= 12 ? titleParts[1].trim() : null) ||
|
|
201
|
+
(h1List[0] && h1List[0].length <= 75 ? h1List[0] : null) ||
|
|
202
|
+
(description ? description.slice(0, 60).trim() : `Automated workflow and growth engine for ${cleanName}`);
|
|
203
|
+
|
|
204
|
+
const launchKit = generateLaunchKit({
|
|
205
|
+
origin: parsedUrl.origin,
|
|
206
|
+
domain,
|
|
207
|
+
slug,
|
|
208
|
+
cleanName,
|
|
209
|
+
tagline: extractedTagline,
|
|
210
|
+
description,
|
|
211
|
+
h1List,
|
|
212
|
+
h2List,
|
|
213
|
+
botEmail
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Generate 25 Programmatic SEO page blueprints tailored to this domain/slug
|
|
217
|
+
const pseoPages = generatePseoPages(parsedUrl.origin, slug, cleanName);
|
|
218
|
+
|
|
219
|
+
// Generate ready-to-drop SEO & Paywall code artifacts (with all 25 pSEO routes in sitemap.xml)
|
|
220
|
+
const artifacts = generateArtifacts(
|
|
221
|
+
parsedUrl.origin,
|
|
222
|
+
slug,
|
|
223
|
+
cleanName,
|
|
224
|
+
description || launchKit.shortPitch,
|
|
225
|
+
pseoPages
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
// Attach prefilled submission URLs for all 85 directories
|
|
229
|
+
const enrichedDirectories = DIRECTORIES.map(dir => ({
|
|
230
|
+
...dir,
|
|
231
|
+
status: "Queued",
|
|
232
|
+
prefilledUrl: buildPrefilledDirectoryUrl(dir, launchKit)
|
|
233
|
+
}));
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
targetUrl: parsedUrl.origin,
|
|
237
|
+
domain,
|
|
238
|
+
slug,
|
|
239
|
+
cleanName,
|
|
240
|
+
reachable,
|
|
241
|
+
botEmail,
|
|
242
|
+
readinessScore,
|
|
243
|
+
checks,
|
|
244
|
+
launchKit,
|
|
245
|
+
pseoPages,
|
|
246
|
+
artifacts,
|
|
247
|
+
directoryCount: enrichedDirectories.length,
|
|
248
|
+
directories: enrichedDirectories
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function generateLaunchKit({ origin, domain, slug, cleanName, tagline, description, h1List, h2List, botEmail }) {
|
|
253
|
+
const cleanTagline = tagline.length > 64 ? tagline.slice(0, 61).trim() + "..." : tagline;
|
|
254
|
+
const shortPitch =
|
|
255
|
+
description && description.length >= 40
|
|
256
|
+
? description.slice(0, 158)
|
|
257
|
+
: `${cleanName} (${domain}) helps teams and solo builders automate their workflow, eliminate manual bottlenecks, and ship faster.`;
|
|
258
|
+
|
|
259
|
+
const featureBullets =
|
|
260
|
+
h2List.length >= 2
|
|
261
|
+
? h2List.slice(0, 4).map(h => `- **${h}**`).join("\n")
|
|
262
|
+
: [
|
|
263
|
+
`- **Instant Setup**: Point ${cleanName} at your live workflow and start in under 60 seconds.`,
|
|
264
|
+
`- **Automated Execution**: Replaces repetitive manual checklists with deterministic automation.`,
|
|
265
|
+
`- **Built for Builders**: Clean CLI and web workspace designed for high-velocity shipping.`
|
|
266
|
+
].join("\n");
|
|
267
|
+
|
|
268
|
+
const utmUrl = `${origin}/?utm_source=postbuild&utm_medium=directory&utm_campaign=${slug}_launch`;
|
|
269
|
+
const categories = inferCategories(`${cleanName} ${cleanTagline} ${shortPitch} ${h1List.join(" ")} ${h2List.join(" ")}`);
|
|
270
|
+
|
|
271
|
+
const longDescription = `${cleanName} — ${cleanTagline}
|
|
272
|
+
|
|
273
|
+
${shortPitch}
|
|
274
|
+
|
|
275
|
+
### Key Highlights
|
|
276
|
+
${featureBullets}
|
|
277
|
+
|
|
278
|
+
Try it live: ${utmUrl}`;
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
productName: cleanName,
|
|
282
|
+
domain,
|
|
283
|
+
targetUrl: origin,
|
|
284
|
+
utmUrl,
|
|
285
|
+
makerEmail: botEmail,
|
|
286
|
+
tagline: cleanTagline,
|
|
287
|
+
shortPitch,
|
|
288
|
+
showHnTitle: `Show HN: ${cleanName} – ${cleanTagline}`,
|
|
289
|
+
categories,
|
|
290
|
+
longDescription
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function generatePseoPages(origin, slug, cleanName) {
|
|
295
|
+
const templates = [
|
|
296
|
+
{ path: `/use-cases/${slug}-for-solo-founders`, keyword: `best ${slug} workflow for solo founders`, volume: "1,400/mo", kd: 12, intent: "Transactional" },
|
|
297
|
+
{ path: `/use-cases/${slug}-automation-guide`, keyword: `how to automate tasks with ${cleanName}`, volume: "2,100/mo", kd: 15, intent: "High Intent" },
|
|
298
|
+
{ path: `/compare/${slug}-vs-manual-workflow`, keyword: `${cleanName} vs manual spreadsheets`, volume: "880/mo", kd: 8, intent: "Comparison" },
|
|
299
|
+
{ path: `/templates/${slug}-starter-kit`, keyword: `free ${slug} template download`, volume: "3,200/mo", kd: 18, intent: "Lead Magnet" },
|
|
300
|
+
{ path: `/alternatives/best-${slug}-alternatives-2026`, keyword: `top ${slug} tools for small teams`, volume: "1,950/mo", kd: 14, intent: "Comparison" },
|
|
301
|
+
{ path: `/calculators/${slug}-roi-calculator`, keyword: `${slug} time & cost calculator`, volume: "1,150/mo", kd: 9, intent: "Interactive" },
|
|
302
|
+
{ path: `/guides/${slug}-api-integration`, keyword: `connect ${cleanName} to webhook & API`, volume: "740/mo", kd: 7, intent: "Developer" },
|
|
303
|
+
{ path: `/use-cases/${slug}-for-agencies`, keyword: `${slug} client reporting for agencies`, volume: "1,600/mo", kd: 16, intent: "B2B Impulse" },
|
|
304
|
+
{ path: `/checklists/${slug}-launch-checklist`, keyword: `complete ${slug} setup checklist`, volume: "2,400/mo", kd: 11, intent: "Lead Magnet" },
|
|
305
|
+
{ path: `/compare/${slug}-pricing-breakdown`, keyword: `is ${cleanName} worth it pricing guide`, volume: "620/mo", kd: 5, intent: "Bottom Funnel" },
|
|
306
|
+
{ path: `/use-cases/${slug}-for-developers`, keyword: `${slug} CLI and developer workflow`, volume: "1,320/mo", kd: 10, intent: "Transactional" },
|
|
307
|
+
{ path: `/use-cases/${slug}-for-indie-hackers`, keyword: `${cleanName} for indie SaaS launches`, volume: "1,780/mo", kd: 11, intent: "Transactional" },
|
|
308
|
+
{ path: `/compare/${slug}-vs-legacy-tools`, keyword: `why switch to ${cleanName} in 2026`, volume: "540/mo", kd: 6, intent: "Comparison" },
|
|
309
|
+
{ path: `/guides/${slug}-programmatic-seo-setup`, keyword: `automated seo setup with ${cleanName}`, volume: "1,490/mo", kd: 13, intent: "High Intent" },
|
|
310
|
+
{ path: `/templates/${slug}-nextjs-boilerplate`, keyword: `${slug} nextjs integration template`, volume: "960/mo", kd: 9, intent: "Developer" },
|
|
311
|
+
{ path: `/use-cases/${slug}-for-saas-teams`, keyword: `scale b2b saas with ${cleanName}`, volume: "1,120/mo", kd: 14, intent: "B2B Impulse" },
|
|
312
|
+
{ path: `/guides/${slug}-stripe-checkout-guide`, keyword: `add self-serve checkout with ${cleanName}`, volume: "830/mo", kd: 8, intent: "Transactional" },
|
|
313
|
+
{ path: `/checklists/${slug}-seo-audit-checklist`, keyword: `technical seo audit checklist ${slug}`, volume: "2,050/mo", kd: 15, intent: "Lead Magnet" },
|
|
314
|
+
{ path: `/calculators/${slug}-conversion-estimator`, keyword: `saas launch conversion rate calculator`, volume: "1,280/mo", kd: 10, intent: "Interactive" },
|
|
315
|
+
{ path: `/alternatives/${slug}-open-source-comparison`, keyword: `${cleanName} vs open source scripts`, volume: "690/mo", kd: 7, intent: "Comparison" },
|
|
316
|
+
{ path: `/use-cases/${slug}-for-product-hunt-launch`, keyword: `prepare product hunt launch with ${cleanName}`, volume: "1,540/mo", kd: 12, intent: "High Intent" },
|
|
317
|
+
{ path: `/guides/${slug}-ai-search-indexing`, keyword: `get indexed on chatgpt and perplexity with ${slug}`, volume: "2,650/mo", kd: 11, intent: "High Intent" },
|
|
318
|
+
{ path: `/templates/${slug}-directory-submission-kit`, keyword: `85 startup directory submission list 2026`, volume: "3,400/mo", kd: 16, intent: "Lead Magnet" },
|
|
319
|
+
{ path: `/use-cases/${slug}-for-ai-wrappers`, keyword: `monetize ai apps with ${cleanName}`, volume: "1,890/mo", kd: 13, intent: "Transactional" },
|
|
320
|
+
{ path: `/compare/${slug}-roi-case-study`, keyword: `${cleanName} traffic and revenue case study`, volume: "480/mo", kd: 4, intent: "Bottom Funnel" }
|
|
321
|
+
];
|
|
322
|
+
|
|
323
|
+
return templates.map((t, idx) => ({
|
|
324
|
+
id: `pseo-${idx + 1}`,
|
|
325
|
+
url: `${origin}${t.path}`,
|
|
326
|
+
path: t.path,
|
|
327
|
+
keyword: t.keyword,
|
|
328
|
+
volume: t.volume,
|
|
329
|
+
kd: `KD ${t.kd}`,
|
|
330
|
+
intent: t.intent,
|
|
331
|
+
status: "Generated"
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function generateArtifacts(origin, slug, cleanName, description, pseoPages) {
|
|
336
|
+
const today = new Date().toISOString().split("T")[0];
|
|
337
|
+
|
|
338
|
+
const routeEntries = pseoPages
|
|
339
|
+
.map(
|
|
340
|
+
p => ` <url>
|
|
341
|
+
<loc>${origin}${p.path}</loc>
|
|
342
|
+
<lastmod>${today}</lastmod>
|
|
343
|
+
<changefreq>weekly</changefreq>
|
|
344
|
+
<priority>0.8</priority>
|
|
345
|
+
</url>`
|
|
346
|
+
)
|
|
347
|
+
.join("\n");
|
|
348
|
+
|
|
349
|
+
const sitemapXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
350
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
351
|
+
<url>
|
|
352
|
+
<loc>${origin}/</loc>
|
|
353
|
+
<lastmod>${today}</lastmod>
|
|
354
|
+
<changefreq>daily</changefreq>
|
|
355
|
+
<priority>1.0</priority>
|
|
356
|
+
</url>
|
|
357
|
+
${routeEntries}
|
|
358
|
+
</urlset>`;
|
|
359
|
+
|
|
360
|
+
const robotsTxt = `User-agent: *
|
|
361
|
+
Allow: /
|
|
362
|
+
|
|
363
|
+
# AI Search Crawlers (ChatGPT Search, Perplexity, Claude, Google Gemini)
|
|
364
|
+
User-agent: OAI-SearchBot
|
|
365
|
+
Allow: /
|
|
366
|
+
User-agent: PerplexityBot
|
|
367
|
+
Allow: /
|
|
368
|
+
User-agent: ClaudeBot
|
|
369
|
+
Allow: /
|
|
370
|
+
|
|
371
|
+
Sitemap: ${origin}/sitemap.xml`;
|
|
372
|
+
|
|
373
|
+
const jsonLd = `<script type="application/ld+json">
|
|
374
|
+
{
|
|
375
|
+
"@context": "https://schema.org",
|
|
376
|
+
"@type": "SoftwareApplication",
|
|
377
|
+
"name": "${cleanName.replace(/"/g, '\\"')}",
|
|
378
|
+
"url": "${origin}",
|
|
379
|
+
"applicationCategory": "BusinessApplication",
|
|
380
|
+
"operatingSystem": "Web",
|
|
381
|
+
"description": "${description.replace(/"/g, '\\"')}",
|
|
382
|
+
"offers": {
|
|
383
|
+
"@type": "Offer",
|
|
384
|
+
"price": "29.00",
|
|
385
|
+
"priceCurrency": "USD"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
</script>`;
|
|
389
|
+
|
|
390
|
+
const paywallCode = `// Postbuild Drop-In Stripe Checkout Gate (${cleanName})
|
|
391
|
+
export async function triggerPostbuildCheckout(plan = "launch_pass", domain = "${slug}.com") {
|
|
392
|
+
const res = await fetch("/api/checkout", {
|
|
393
|
+
method: "POST",
|
|
394
|
+
headers: { "Content-Type": "application/json" },
|
|
395
|
+
body: JSON.stringify({ plan, domain })
|
|
396
|
+
});
|
|
397
|
+
const data = await res.json();
|
|
398
|
+
if (data.checkoutUrl) window.location.href = data.checkoutUrl;
|
|
399
|
+
return data;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export function PostbuildCheckoutGate({ domain = "${slug}.com" }) {
|
|
403
|
+
return (
|
|
404
|
+
<button
|
|
405
|
+
type="button"
|
|
406
|
+
onClick={() => triggerPostbuildCheckout("launch_pass", domain)}
|
|
407
|
+
style={{
|
|
408
|
+
display: "inline-flex",
|
|
409
|
+
alignItems: "center",
|
|
410
|
+
gap: "8px",
|
|
411
|
+
padding: "10px 18px",
|
|
412
|
+
borderRadius: "8px",
|
|
413
|
+
background: "#09090b",
|
|
414
|
+
color: "#ffffff",
|
|
415
|
+
fontWeight: 600,
|
|
416
|
+
fontSize: "13px",
|
|
417
|
+
border: "1px solid #09090b",
|
|
418
|
+
cursor: "pointer"
|
|
419
|
+
}}
|
|
420
|
+
>
|
|
421
|
+
<span>Get Launch Pass — $29</span>
|
|
422
|
+
</button>
|
|
423
|
+
);
|
|
424
|
+
}`;
|
|
425
|
+
|
|
426
|
+
return { sitemapXml, robotsTxt, jsonLd, paywallCode };
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export async function dispatchDirectories({ targetUrl = "https://postbuild.dev", directoryIds = [] }) {
|
|
430
|
+
const scan = await scanTargetUrl(targetUrl);
|
|
431
|
+
const selected =
|
|
432
|
+
Array.isArray(directoryIds) && directoryIds.length > 0
|
|
433
|
+
? scan.directories.filter(d => directoryIds.includes(d.id))
|
|
434
|
+
: scan.directories;
|
|
435
|
+
|
|
436
|
+
const timestamp = new Date().toISOString();
|
|
437
|
+
const results = selected.map(dir => ({
|
|
438
|
+
id: dir.id,
|
|
439
|
+
name: dir.name,
|
|
440
|
+
category: dir.category,
|
|
441
|
+
dr: dir.dr,
|
|
442
|
+
authType: dir.authType,
|
|
443
|
+
submissionUrl: dir.url,
|
|
444
|
+
prefilledUrl: dir.prefilledUrl,
|
|
445
|
+
botEmail: scan.botEmail,
|
|
446
|
+
status: "Dispatched",
|
|
447
|
+
dispatchedAt: timestamp
|
|
448
|
+
}));
|
|
449
|
+
|
|
450
|
+
return {
|
|
451
|
+
ok: true,
|
|
452
|
+
domain: scan.domain,
|
|
453
|
+
botEmail: scan.botEmail,
|
|
454
|
+
launchKit: scan.launchKit,
|
|
455
|
+
totalDispatched: results.length,
|
|
456
|
+
results
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export async function searchBuyerIntentRadar(query) {
|
|
461
|
+
const searchTerms = (query || "marketing automation seo indie hacker").trim();
|
|
462
|
+
const url = `https://hn.algolia.com/api/v1/search_by_date?query=${encodeURIComponent(searchTerms)}&tags=story&hitsPerPage=8`;
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
|
466
|
+
if (!res.ok) throw new Error("HN API status " + res.status);
|
|
467
|
+
const data = await res.json();
|
|
468
|
+
const hits = (data.hits || []).map((h, idx) => ({
|
|
469
|
+
id: h.objectID || `hn-${idx}`,
|
|
470
|
+
source: "Hacker News",
|
|
471
|
+
title: h.title || "Discussion thread",
|
|
472
|
+
author: h.author || "founder",
|
|
473
|
+
createdAt: h.created_at ? h.created_at.split("T")[0] : "Recent",
|
|
474
|
+
url: h.url || `https://news.ycombinator.com/item?id=${h.objectID}`,
|
|
475
|
+
discussionUrl: `https://news.ycombinator.com/item?id=${h.objectID}`,
|
|
476
|
+
points: h.points || 1,
|
|
477
|
+
comments: h.num_comments || 0,
|
|
478
|
+
locked: idx >= 3,
|
|
479
|
+
draftReply: `Hey @${h.author || "there"} — ran into this exact bottleneck after finishing a build. I ended up running \`git paid\` (https://postbuild.dev) to auto-generate 25 programmatic SEO routes, provision a @postbuild.dev verification inbox, and dispatch to 85 directories.`
|
|
480
|
+
}));
|
|
481
|
+
|
|
482
|
+
if (hits.length > 0) return hits;
|
|
483
|
+
} catch {
|
|
484
|
+
// Fallback if offline
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return [
|
|
488
|
+
{
|
|
489
|
+
id: "fallback-1",
|
|
490
|
+
source: "Hacker News",
|
|
491
|
+
title: "Ask HN: How are solo devs handling SEO and directory launches after building?",
|
|
492
|
+
author: "dev_minimalist",
|
|
493
|
+
createdAt: "Today",
|
|
494
|
+
url: "https://news.ycombinator.com/ask",
|
|
495
|
+
discussionUrl: "https://news.ycombinator.com/ask",
|
|
496
|
+
points: 42,
|
|
497
|
+
comments: 29,
|
|
498
|
+
locked: false,
|
|
499
|
+
draftReply: "I built Postbuild (https://postbuild.dev) for this exact reason — you run `git paid` after `git push` and it provisions a @postbuild.dev bot email, generates 25 programmatic SEO pages, and dispatches to 85 directories."
|
|
500
|
+
}
|
|
501
|
+
];
|
|
502
|
+
}
|