import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import test from "node:test"; const routeSource = readFileSync( new URL("../src/app/api/reports/[reportId]/professional-reference/route.ts", import.meta.url), "utf8", ); const frontendRoot = fileURLToPath(new URL("../", import.meta.url)); function executeReadyReportExport() { const script = String.raw` import { mock } from "node:test"; import { pathToFileURL } from "node:url"; import { Agent } from "@mastra/core/agent"; const moduleUrl = (path) => pathToFileURL(process.cwd() + "/" + path).href; // Node 22 ignores the unsupported exports mock option; keep the route aliases explicit. mock.module("@/lib/personal-report-entitlement", { namedExports: { checkSameOrigin: () => ({ ok: true }), resolveAllowedReportOrigins: () => [], }}); mock.module("@/lib/personal-report-service", { namedExports: { createSupabasePersonalReportService: () => ({ getOwnedById: async () => ({ status: "ready", requestId: "123e4567-e89b-12d3-a456-426614174111" }), }), }}); mock.module("@/lib/supabase/admin", { namedExports: { createAdminSupabaseClient: () => { throw new Error("admin unused in this unit test"); }, }}); mock.module("@/lib/report-candidate-range", { namedExports: { loadReportCandidateRange: async () => null, }}); mock.module("@/lib/personal-report-longform-appendix", { namedExports: { LONGFORM_APPENDIX_TABLE: "personal_report_longform_appendices", parseLongformAppendixRow: () => null, nextLongformAppendixState: () => ({ status: "ready", attemptCount: 0, markdown: "# Professional reference", contentSha256: "ab", lastErrorCode: null }), }}); mock.module("@/lib/supabase/config", { namedExports: { isSupabaseConfigurationError: () => false, }}); const profileQuery = { select() { return this; }, eq() { return this; }, async maybeSingle() { return { data: { birth_date: "1990-01-02", reported_birth_time: "03:04", latitude: 39.9, longitude: 116.4, timezone_offset: 8, ayanamsa: "lahiri", }, error: null }; }, }; mock.module("@/lib/supabase/server", { namedExports: { createServerSupabaseClient: async () => ({ auth: { getUser: async () => ({ data: { user: { id: "user-1" } }, error: null }) }, from: () => profileQuery, }), }}); let modelCalls = 0; Agent.prototype.generate = async () => { modelCalls += 1; throw new Error("professional export must not call a model"); }; let telemetryEvents = 0; console.info = (...args) => { if (args[0] === "[personal-report-agent]") telemetryEvents += 1; }; const upstream = []; globalThis.fetch = async (input, init) => { upstream.push({ url: String(input), method: init?.method, body: JSON.parse(String(init?.body)), }); return new Response(JSON.stringify({ format: "markdown", markdown: "# Professional reference" }), { status: 200, headers: { "content-type": "application/json" }, }); }; const { POST } = await import(moduleUrl("src/app/api/reports/[reportId]/professional-reference/route.ts")); const response = await POST( new Request("https://staging.jyotisha.chat/api/reports/123e4567-e89b-12d3-a456-426614174000/professional-reference", { method: "POST", headers: { origin: "https://staging.jyotisha.chat" }, }), { params: Promise.resolve({ reportId: "123e4567-e89b-12d3-a456-426614174000" }) }, ); console.log(JSON.stringify({ status: response.status, body: await response.json(), modelCalls, telemetryEvents, upstream, })); `; const result = spawnSync(process.execPath, [ "--experimental-test-module-mocks", "--import", "tsx", "--input-type=module", "--eval", script, ], { cwd: frontendRoot, encoding: "utf8" }); assert.equal(result.status, 0, result.stderr || result.stdout); return JSON.parse(result.stdout.trim()) as { status: number; body: { format: string; markdown: string }; modelCalls: number; telemetryEvents: number; upstream: Array<{ url: string; method: string; body: Record }>; }; } test("professional reference route authenticates, checks origin, owner and ready status", () => { assert.match(routeSource, /createServerSupabaseClient/); assert.match(routeSource, /supabase\.auth\.getUser\(\)/); assert.match(routeSource, /checkSameOrigin/); assert.match(routeSource, /resolveAllowedReportOrigins/); assert.match(routeSource, /getOwnedById\(user\.id, reportId\)/); assert.match(routeSource, /report\.status !== "ready"/); assert.match(routeSource, /status: 401/); assert.match(routeSource, /status: 403/); assert.match(routeSource, /status: 404/); assert.match(routeSource, /status: 409/); }); test("birth data stays server-owned and the route calls only the public Python export", () => { assert.match(routeSource, /\.from\("profiles"\)/); assert.match(routeSource, /select\(ACCOUNT_BIRTH_SELECT\)/); assert.match(routeSource, /globalBirthProfileFromAccountRow/); assert.match(routeSource, /\/api\/professional_report_reference/); assert.match(routeSource, /format: "markdown"/); assert.match(routeSource, /packs: \["full"\]/); assert.match(routeSource, /target_year/); assert.match(routeSource, /birth_time_accuracy/); assert.match(routeSource, /loadReportCandidateRange/); assert.match(routeSource, /LONGFORM_APPENDIX_TABLE/); assert.match(routeSource, /from "@\/lib\/personal-report-longform-appendix"/); assert.doesNotMatch(routeSource, /request\.json\(/); assert.doesNotMatch(routeSource, /mastra|writer|billing|personal_report_sections/i); assert.doesNotMatch(routeSource, /from\("personal_reports"\)/); }); test("ready report export calls the Python endpoint without model calls or writer telemetry", () => { const result = executeReadyReportExport(); assert.equal(result.status, 200); assert.deepEqual(result.body, { format: "markdown", markdown: "# Professional reference" }); assert.equal(result.modelCalls, 0); assert.equal(result.telemetryEvents, 0); assert.equal(result.upstream.length, 1); assert.equal(result.upstream[0].url, "http://127.0.0.1:5200/api/professional_report_reference"); assert.equal(result.upstream[0].method, "POST"); assert.equal(result.upstream[0].body.year, 1990); assert.equal(result.upstream[0].body.month, 1); assert.equal(result.upstream[0].body.day, 2); assert.equal(result.upstream[0].body.hour, 3); assert.equal(result.upstream[0].body.minute, 4); assert.equal(result.upstream[0].body.lat, 39.9); assert.equal(result.upstream[0].body.lon, 116.4); assert.equal(result.upstream[0].body.tz, 8); assert.equal(result.upstream[0].body.ayanamsa, "lahiri"); assert.equal(result.upstream[0].body.format, "markdown"); assert.deepEqual(result.upstream[0].body.packs, ["full"]); assert.match(String(result.upstream[0].body.today), /^\d{4}-\d{2}-\d{2}$/); assert.equal(result.upstream[0].body.target_year, Number(String(result.upstream[0].body.today).slice(0, 4))); assert.equal(result.upstream[0].body.age, Number(result.upstream[0].body.target_year) - 1990); assert.equal(result.upstream[0].body.birth_time_accuracy, "confirmed"); assert.equal(result.upstream[0].body.candidate_range, undefined); }); test("busy upstream responses preserve 429 and Retry-After", () => { assert.match(routeSource, /upstream\.status/); assert.match(routeSource, /upstream\.headers\.get\("retry-after"\)/); assert.match(routeSource, /"Retry-After": retryAfter/); });