From 90f7726e6799e906247b17489e19c883b8dfb04e Mon Sep 17 00:00:00 2001 From: divyanshujethi Date: Wed, 11 Nov 2026 01:53:00 +0530 Subject: [PATCH] fix(monetization): route private core repos per SKU, align exact checkout prices, and clean placeholder affiliate refs --- src/app/fineprint/page.tsx | 66 ++++++++++++++++++++----------- src/app/mockforge/page.tsx | 66 ++++++++++++++++++++----------- src/app/pricing/page.tsx | 12 +++--- src/app/pricing/success/page.tsx | 7 +++- src/app/promptshield/page.tsx | 66 ++++++++++++++++++++----------- src/data/affiliates.json | 39 +++++++++++------- src/lib/checkout-urls.d.ts | 5 ++- src/lib/checkout-urls.js | 27 +++++++++++++ src/lib/dodo-webhook.d.ts | 6 +++ src/lib/dodo-webhook.js | 28 +++++++++++-- tests/checkout-functions.test.mjs | 48 ++++++++++++++++++++++ 11 files changed, 274 insertions(+), 96 deletions(-) diff --git a/src/app/fineprint/page.tsx b/src/app/fineprint/page.tsx index b2d308d..eb23baf 100644 --- a/src/app/fineprint/page.tsx +++ b/src/app/fineprint/page.tsx @@ -24,6 +24,7 @@ import { PenTool, ShieldAlert } from "lucide-react"; +import TeamCheckoutBanner from "@/components/TeamCheckoutBanner"; export default function FinePrintPage() { const [copied, setCopied] = useState(null); @@ -136,9 +137,7 @@ export default function FinePrintPage() { Upgrade to Corporate Playbook Pro ($79/mo) @@ -287,26 +286,47 @@ export default function FinePrintPage() { - {/* CTA Box */} -
-

Protect Your Company from Asymmetric Contracts

-

- Never sign an agreement without running FinePrint AI. Scan contracts locally or automate review via DocuSign webhooks. -

-
- - Download Free Community CLI - - - Deploy Corporate Playbook Pro ($79/mo) - -
+
+
diff --git a/src/app/mockforge/page.tsx b/src/app/mockforge/page.tsx index de60114..6baf9e4 100644 --- a/src/app/mockforge/page.tsx +++ b/src/app/mockforge/page.tsx @@ -23,6 +23,7 @@ import { Play, FileSpreadsheet } from "lucide-react"; +import TeamCheckoutBanner from "@/components/TeamCheckoutBanner"; export default function MockForgePage() { const [copied, setCopied] = useState(null); @@ -192,9 +193,7 @@ CREATE TABLE prescriptions (rx_id INT PRIMARY KEY, encounter_id INT REFERENCES e Upgrade to Production Masking Pro ($49/mo) @@ -344,26 +343,47 @@ CREATE TABLE prescriptions (rx_id INT PRIMARY KEY, encounter_id INT REFERENCES e - {/* CTA Box */} -
-

Generate Coherent Test Data in Seconds

-

- Stop writing brittle manual SQL seed fixtures. Run MockForge locally or integrate into your CI/CD test runners. -

-
- - Download Free Community CLI - - - Purchase Production Masking Pro ($49/mo) - -
+
+
diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index 9826299..884694a 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -535,23 +535,23 @@ export default function PricingPage() {

PromptShield, MockForge & FinePrint

- Commercial Pro license for browser DLP firewall, production DB masking & legal contract redlines. + Commercial Pro license + private core repo access (`PromptShield-Core`, `MockForge-Core`, `FinePrintAI-Core`).

- Ritual Pro License ($15/mo) + Pro Core Access ($49/mo)
- PromptShield ·{" "} - MockForge ·{" "} - FinePrint + PromptShield ($49) ·{" "} + MockForge ($49) ·{" "} + FinePrint ($79)
diff --git a/src/app/pricing/success/page.tsx b/src/app/pricing/success/page.tsx index 3623ea4..66d351c 100644 --- a/src/app/pricing/success/page.tsx +++ b/src/app/pricing/success/page.tsx @@ -11,7 +11,12 @@ function PricingSuccessContent() { const paymentId = searchParams.get("payment_id") || searchParams.get("id") || "PENDING_WEBHOOK"; const product = (searchParams.get("product") || "team_relay_29").toLowerCase(); - const isPrivateKit = product.includes("private") || product.includes("compliance"); + const isPrivateKit = + product.includes("private") || + product.includes("compliance") || + product.includes("promptshield") || + product.includes("mockforge") || + product.includes("fineprint"); const isMcpPack = product.includes("mcp_pack"); const matchedCfg = TEAM_PRODUCT_CONFIG[product]; const isTeamHub = product.includes("hub") || product.includes("99"); diff --git a/src/app/promptshield/page.tsx b/src/app/promptshield/page.tsx index 39fad6e..17dbe22 100644 --- a/src/app/promptshield/page.tsx +++ b/src/app/promptshield/page.tsx @@ -23,6 +23,7 @@ import { Server, Zap } from "lucide-react"; +import TeamCheckoutBanner from "@/components/TeamCheckoutBanner"; export default function PromptShieldPage() { const [copied, setCopied] = useState(null); @@ -175,9 +176,7 @@ export default function PromptShieldPage() { Upgrade to Enterprise Fleet ($49/mo) @@ -350,26 +349,47 @@ export default function PromptShieldPage() { - {/* CTA Box */} -
-

Stop Accidental AI Leaks Today

-

- Install PromptShield on Chromium-based browsers or integrate PromptShield-Core into your internal developer proxy fleets. -

-
+
+
diff --git a/src/data/affiliates.json b/src/data/affiliates.json index ca5682f..eac1e3b 100644 --- a/src/data/affiliates.json +++ b/src/data/affiliates.json @@ -13,19 +13,21 @@ "perkDescription": "Get $200 in free cloud infrastructure credits to deploy Droplets, Kubernetes, and App Platform instances.", "ctaText": "Claim $200 Credits →", "badge": "🎁 $200 Dev Credit", - "active": true + "active": true, + "affiliateConfigured": true }, { "slug": "hetzner", "toolName": "Hetzner Cloud", - "url": "https://hetzner.cloud/?ref=devshelf", + "url": "https://hetzner.cloud/", "vanityPath": "/go/hetzner.html", "category": "cloud", "perkTitle": "€20 Free Cloud Credits", "perkDescription": "High-performance European and US cloud instances starting at €3.79/mo. Claim €20 in free test credits.", "ctaText": "Claim €20 Credits →", "badge": "🎁 €20 Cloud Credit", - "active": true + "active": true, + "affiliateConfigured": false }, { "slug": "vultr", @@ -37,7 +39,8 @@ "perkDescription": "Global cloud compute, bare metal, and managed Kubernetes across 32 worldwide locations with instant credits.", "ctaText": "Claim $100 Credits →", "badge": "🎁 $100 Cloud Credit", - "active": true + "active": true, + "affiliateConfigured": true }, { "slug": "geekflare", @@ -49,67 +52,73 @@ "perkDescription": "High-speed developer APIs for scraping, data extraction, and collaborative AI models.", "ctaText": "Explore APIs →", "badge": "⚡ Dev API Perks", - "active": true + "active": true, + "affiliateConfigured": true }, { "slug": "supabase", "toolName": "Supabase", - "url": "https://supabase.com/?ref=devshelf", + "url": "https://supabase.com/", "vanityPath": "/go/supabase.html", "category": "cloud", "perkTitle": "Generous Permanent Free Postgres Tier", "perkDescription": "Full Postgres database, authentication, instant REST/GraphQL APIs, and real-time subscriptions with 500MB storage.", "ctaText": "Launch Free Project →", "badge": "⚡ Verified Free Tier", - "active": true + "active": true, + "affiliateConfigured": false }, { "slug": "neon", "toolName": "Neon", - "url": "https://neon.tech/?ref=devshelf", + "url": "https://neon.tech/", "vanityPath": "/go/neon.html", "category": "cloud", "perkTitle": "Serverless Postgres with Instant Branching", "perkDescription": "Autoscaling, database branching like Git, and zero cold starts with generous free tier allowances.", "ctaText": "Get Free Postgres →", "badge": "⚡ Free Serverless DB", - "active": true + "active": true, + "affiliateConfigured": false }, { "slug": "railway", "toolName": "Railway", - "url": "https://railway.com/?ref=devshelf", + "url": "https://railway.com/", "vanityPath": "/go/railway.html", "category": "cloud", "perkTitle": "$5 Monthly Free Cloud & API Hosting", "perkDescription": "Instant git-push deployments for Node.js, Python, Docker, MCP servers, and Postgres.", "ctaText": "Deploy on Railway ->", "badge": "⚡ Cloud Free Tier", - "active": true + "active": true, + "affiliateConfigured": false }, { "slug": "posthog", "toolName": "PostHog", - "url": "https://posthog.com/?ref=devshelf", + "url": "https://posthog.com/", "vanityPath": "/go/posthog.html", "category": "testing", "perkTitle": "1M Free Events + 5,000 Session Replays/mo", "perkDescription": "Open-source product analytics, feature flags, session replay, and LLM observability.", "ctaText": "Start Free on PostHog ->", "badge": "⚡ 1M Free Events", - "active": true + "active": true, + "affiliateConfigured": false }, { "slug": "cloudflare", "toolName": "Cloudflare", - "url": "https://www.cloudflare.com/?ref=devshelf", + "url": "https://www.cloudflare.com/", "vanityPath": "/go/cloudflare.html", "category": "cloud", "perkTitle": "100,000 Free Daily Worker Invocations + Pages", "perkDescription": "Global edge workers, zero-egress R2 storage, D1 SQLite, and unlimited static sites.", "ctaText": "Launch on Cloudflare ->", "badge": "⚡ Free Edge Workers", - "active": true + "active": true, + "affiliateConfigured": false } ] } diff --git a/src/lib/checkout-urls.d.ts b/src/lib/checkout-urls.d.ts index 942164a..47f4ad1 100644 --- a/src/lib/checkout-urls.d.ts +++ b/src/lib/checkout-urls.d.ts @@ -58,6 +58,9 @@ export type TeamProductTierId = | "agentshield_enterprise_49" | "websec_team_19" | "ritual_pro_15" + | "promptshield_pro_49" + | "mockforge_pro_49" + | "fineprint_pro_79" | "mcp_starter_49" | "mcp_pack_fintech_39" | "mcp_pack_database_49" @@ -83,7 +86,7 @@ export interface CloudOrPrivateCheckoutInput { export const DODO_PRODUCT_IDS: Record; export const TEAM_PRODUCT_CONFIG: Record< string, - { id: string; productId: string; flexAmountUsd?: string; extraParams?: Record; label: string; redirectUrl: string } + { id: string; productId: string; flexAmountUsd?: string; coreRepo?: string; extraParams?: Record; label: string; redirectUrl: string } >; export function resolvePartnerTierPricing( diff --git a/src/lib/checkout-urls.js b/src/lib/checkout-urls.js index e17132d..4d4c88c 100644 --- a/src/lib/checkout-urls.js +++ b/src/lib/checkout-urls.js @@ -327,6 +327,30 @@ export const TEAM_PRODUCT_CONFIG = { label: "Ritual Pro Individual Suite License ($15/mo)", redirectUrl: "https://ritualdev.in/pricing/success/?product=ritual_pro_15", }, + promptshield_pro_49: { + id: "promptshield_pro_49", + productId: DODO_SERVICE_FLEX, + flexAmountUsd: "49", + coreRepo: "RitualDev-Lab/PromptShield-Core", + label: "PromptShield Enterprise Fleet + PromptShield-Core ($49/mo)", + redirectUrl: "https://ritualdev.in/pricing/success/?product=promptshield_pro_49", + }, + mockforge_pro_49: { + id: "mockforge_pro_49", + productId: DODO_SERVICE_FLEX, + flexAmountUsd: "49", + coreRepo: "RitualDev-Lab/MockForge-Core", + label: "MockForge Production Masking Pro + MockForge-Core ($49/mo)", + redirectUrl: "https://ritualdev.in/pricing/success/?product=mockforge_pro_49", + }, + fineprint_pro_79: { + id: "fineprint_pro_79", + productId: DODO_SERVICE_FLEX, + flexAmountUsd: "79", + coreRepo: "RitualDev-Lab/FinePrintAI-Core", + label: "FinePrint Corporate Playbook Pro + FinePrintAI-Core ($79/mo)", + redirectUrl: "https://ritualdev.in/pricing/success/?product=fineprint_pro_79", + }, mcp_starter_49: { id: "mcp_starter_49", productId: DODO_MCP_STARTER_49, @@ -419,6 +443,9 @@ export function buildTeamProductCheckoutUrl({ if (githubUsername) { params.set("metadata_github_username", githubUsername.trim().replace(/^@/, "")); } + if (cfg.coreRepo) { + params.set("metadata_coreRepo", cfg.coreRepo); + } params.set("metadata_tier", cfg.id); params.set("redirect_url", cfg.redirectUrl); return `https://checkout.dodopayments.com/buy/${cfg.productId}?${params.toString()}`; diff --git a/src/lib/dodo-webhook.d.ts b/src/lib/dodo-webhook.d.ts index 4279c07..f141e06 100644 --- a/src/lib/dodo-webhook.d.ts +++ b/src/lib/dodo-webhook.d.ts @@ -7,6 +7,12 @@ export function verifyDodoWebhookSignature(params: { nowMs?: number; }): Promise; +export function resolvePrivateRepoForOrder(params: { + tier?: string; + metadata?: Record; + env?: Record; +}): string; + export function inviteGitHubCollaborator(params: { repoSlug: string; username: string; diff --git a/src/lib/dodo-webhook.js b/src/lib/dodo-webhook.js index db16e8d..c03abb9 100644 --- a/src/lib/dodo-webhook.js +++ b/src/lib/dodo-webhook.js @@ -71,6 +71,23 @@ export async function verifyDodoWebhookSignature({ return false; } +export function resolvePrivateRepoForOrder({ tier = "", metadata = {}, env = {} }) { + const explicit = String(metadata?.coreRepo || metadata?.repo || "").trim().toLowerCase(); + const t = String(tier || "").toLowerCase(); + const combined = `${t} ${explicit}`; + + if (combined.includes("promptshield")) { + return env?.PRIVATE_PROMPTSHIELD_REPO || "RitualDev-Lab/PromptShield-Core"; + } + if (combined.includes("mockforge")) { + return env?.PRIVATE_MOCKFORGE_REPO || "RitualDev-Lab/MockForge-Core"; + } + if (combined.includes("fineprint")) { + return env?.PRIVATE_FINEPRINT_REPO || "RitualDev-Lab/FinePrintAI-Core"; + } + return env?.PRIVATE_COMPLIANCE_REPO || ""; +} + export async function inviteGitHubCollaborator({ repoSlug, username, githubPat }) { if (!repoSlug || !username || !githubPat) { return { invited: false, reason: "Missing GITHUB_PAT, repoSlug, or github_username" }; @@ -252,6 +269,7 @@ export async function handleDodoWebhookEvent({ rawBody, headers, env }) { const toolUrl = metadata?.toolUrl || metadata?.tool_url || metadata?.url; const orderId = metadata?.orderId || ""; const isSponsorPayment = SPONSOR_TIER_MAP.has(tier) || orderId.startsWith("SPONSOR-") || Boolean(toolName && toolUrl); + const targetPrivateRepo = resolvePrivateRepoForOrder({ tier, metadata, env }); if (isSponsorPayment) { const activation = await dispatchDevShelfSponsorActivation({ @@ -268,15 +286,17 @@ export async function handleDodoWebhookEvent({ rawBody, headers, env }) { fulfillmentNote = activation.dispatched ? `Dispatched DevShelf activate-sponsor.yml workflow (tier: ${activation.workflowTier})` : `DevShelf workflow dispatch pending manual review: ${activation.reason || `HTTP ${activation.status}`}`; - } else if (ghUser && env?.GITHUB_PAT && env?.PRIVATE_COMPLIANCE_REPO) { + } else if (targetPrivateRepo && ghUser && env?.GITHUB_PAT) { const invite = await inviteGitHubCollaborator({ - repoSlug: env.PRIVATE_COMPLIANCE_REPO, + repoSlug: targetPrivateRepo, username: ghUser, githubPat: env.GITHUB_PAT, }); fulfillmentNote = invite.invited - ? `GitHub collaborator invited (@${invite.username} -> ${env.PRIVATE_COMPLIANCE_REPO})` - : `GitHub invite skipped/failed: ${invite.reason || `HTTP ${invite.status}`}`; + ? `GitHub collaborator invited (@${invite.username} -> ${targetPrivateRepo})` + : `GitHub invite skipped/failed (${targetPrivateRepo}): ${invite.reason || `HTTP ${invite.status}`}`; + } else if (targetPrivateRepo) { + fulfillmentNote = `Pending GitHub invite to ${targetPrivateRepo} for ${customerEmail} (handle=${ghUser || "missing"}, tier=${tier})`; } else if ( tier.includes("dbshield") || tier.includes("skillprism") || diff --git a/tests/checkout-functions.test.mjs b/tests/checkout-functions.test.mjs index 94c942d..58b75c9 100644 --- a/tests/checkout-functions.test.mjs +++ b/tests/checkout-functions.test.mjs @@ -376,5 +376,53 @@ describe("Storefront Checkout URL Builders & Cloudflare Pages Functions", () => }); assert.equal(res.ok, true); assert.ok(res.fulfillmentNote.includes("Provision Hosted Team Relay / Governance tenant")); + + // Verify Private Core Repo routing for PromptShield-Core, MockForge-Core, FinePrintAI-Core + const ps49 = buildTeamProductCheckoutUrl({ tier: "promptshield_pro_49", githubUsername: "@alice" }); + assert.ok(ps49.includes("paymentAmount=49")); + assert.ok(ps49.includes("PromptShield-Core")); + assert.ok(ps49.includes("metadata_github_username=alice")); + + const mf49 = buildTeamProductCheckoutUrl({ tier: "mockforge_pro_49" }); + assert.ok(mf49.includes("paymentAmount=49")); + assert.ok(mf49.includes("MockForge-Core")); + + const fp79 = buildTeamProductCheckoutUrl({ tier: "fineprint_pro_79" }); + assert.ok(fp79.includes("paymentAmount=79")); + assert.ok(fp79.includes("FinePrintAI-Core")); + + const coreBody = JSON.stringify({ + type: "payment.succeeded", + data: { + payment_id: "pay_fp_79", + total_amount: 7900, + currency: "USD", + customer: { email: "counsel@acme.io" }, + metadata: { tier: "fineprint_pro_79", github_username: "legalops" }, + }, + }); + const coreSig = crypto.createHmac("sha256", rawSecret).update(`${webhookId}.${ts}.${coreBody}`).digest("base64"); + const origFetch2 = globalThis.fetch; + let inviteUrl = ""; + globalThis.fetch = async (url) => { + inviteUrl = String(url); + return new Response(null, { status: 201 }); + }; + try { + const coreRes = await handleDodoWebhookEvent({ + rawBody: coreBody, + headers: new Headers({ + "webhook-id": webhookId, + "webhook-timestamp": ts, + "webhook-signature": `v1,${coreSig}`, + }), + env: { DODO_WEBHOOK_SECRET: secretB64, GITHUB_PAT: "ghp_testtoken" }, + }); + assert.equal(coreRes.ok, true); + assert.ok(inviteUrl.includes("/repos/RitualDev-Lab/FinePrintAI-Core/collaborators/legalops")); + assert.ok(coreRes.fulfillmentNote.includes("FinePrintAI-Core")); + } finally { + globalThis.fetch = origFetch2; + } }); });