import { v } from "convex/values"; import { internalQuery } from "./_generated/server"; /** * Query the project source metadata the coordinator needs (clone URL, default * branch, org). Internal so the Node action can read it without touching the DB. * * Lives outside the `"use node"` projectSetup module because Convex forbids * query/mutation definitions in Node-runtime modules. */ export const getProjectSource = internalQuery({ args: { projectId: v.id("projects") }, handler: async (ctx, args) => { const project = await ctx.db.get(args.projectId); if (!project) { return null; } return { defaultBranch: project.defaultBranch ?? null, name: project.name, organizationId: project.organizationId, sourceUrl: project.sourceUrl, }; }, }); /** Authorize a retry and read its runtime within the query context. Actions do * not have direct database access, so the authenticated user ID is derived by * the action and verified against the project's organization here. */ export const getRetryableRuntime = internalQuery({ args: { projectId: v.id("projects"), userId: v.string() }, handler: async (ctx, args) => { const project = await ctx.db.get(args.projectId); if (!project) { throw new Error("Project not found"); } const membership = await ctx.db .query("organizationMembers") .withIndex("by_organizationId_and_userId", (q) => q.eq("organizationId", project.organizationId).eq("userId", args.userId) ) .unique(); if (!membership) { throw new Error("Organization membership required"); } const runtime = await ctx.db .query("projectRuntimes") .withIndex("by_projectId", (q) => q.eq("projectId", args.projectId)) .unique(); return { organizationId: project.organizationId, runtime }; }, }); /** * Read-only project setup status for the setup screen: latest runtime row plus * the setup-scoped events. Auth-gated to project members. */ export const getStatus = internalQuery({ args: { projectId: v.id("projects") }, handler: async (ctx, args) => { const project = await ctx.db.get(args.projectId); if (!project) { return { events: [], runtime: null }; } const runtime = await ctx.db .query("projectRuntimes") .withIndex("by_projectId", (q) => q.eq("projectId", args.projectId)) .unique(); const events = await ctx.db .query("events") .withIndex("by_organizationId_and_projectId_and_recordedAt", (q) => q .eq("organizationId", project.organizationId) .eq("projectId", args.projectId) ) .order("desc") .filter((q) => q.or( q.eq(q.field("type"), "project.setup.creating_vm"), q.eq(q.field("type"), "project.setup.cloning"), q.eq(q.field("type"), "project.setup.checking_repository"), q.eq(q.field("type"), "project.ready"), q.eq(q.field("type"), "project.setup.failed"), q.eq(q.field("type"), "project.setup.started") ) ) .take(50); return { events, runtime }; }, });