import process from "node:process" import dotenv from "dotenv" import { ConvexHttpClient } from "convex/browser" import { makeFunctionReference } from "convex/server" const LIST_MANUALS = makeFunctionReference("manuals:list") function canonicalizeDomain(input) { return String(input || "") .trim() .toLowerCase() .replace(/^https?:\/\//, "") .replace(/^\/\//, "") .replace(/\/.*$/, "") .replace(/:\d+$/, "") .replace(/\.$/, "") } function parseArgs(argv) { const domainIndex = argv.indexOf("--domain") const domain = domainIndex >= 0 ? argv[domainIndex + 1] : "" const minCountIndex = argv.indexOf("--min-count") const minCount = minCountIndex >= 0 ? Number.parseInt(argv[minCountIndex + 1] || "", 10) : 1 return { domain, minCount: Number.isFinite(minCount) && minCount > 0 ? minCount : 1, } } function readConvexUrl() { const value = process.env.NEXT_PUBLIC_CONVEX_URL || process.env.CONVEX_URL || "" return value.trim() } async function main() { dotenv.config({ path: ".env.local", override: false }) dotenv.config({ path: ".env.staging", override: false }) const args = parseArgs(process.argv.slice(2)) const domain = canonicalizeDomain( args.domain || process.env.MANUALS_TENANT_DOMAIN || process.env.NEXT_PUBLIC_SITE_DOMAIN ) const convexUrl = readConvexUrl() if (!convexUrl) { throw new Error( "NEXT_PUBLIC_CONVEX_URL (or CONVEX_URL) is required for Convex manuals gate." ) } if (!domain) { throw new Error( "A tenant domain is required. Set NEXT_PUBLIC_SITE_DOMAIN / MANUALS_TENANT_DOMAIN or pass --domain." ) } const convex = new ConvexHttpClient(convexUrl) const manuals = await convex.query(LIST_MANUALS, { domain }) const count = Array.isArray(manuals) ? manuals.length : 0 console.log( `[convex-manuals-gate] domain=${domain} count=${count} min=${args.minCount}` ) if (count < args.minCount) { throw new Error( `Convex manuals gate failed for ${domain}: expected at least ${args.minCount} manuals, got ${count}.` ) } } main().catch((error) => { console.error("[convex-manuals-gate] failed", error) process.exit(1) })