157 lines · 7.6 KB
import { createServerFn } from "@tanstack/react-start";
import { withAuthorAccounts } from "~/server/commit-authors";
import { assertVisibleRevision } from "~/server/git/reachable";
import { z } from "zod";
import { viewerMiddleware } from "./middleware";
import { limitBrowse, limitHeavy } from "~/server/limits";
import { assertRepoReady, requireRepoAccess } from "~/server/repos";
import { listRefs, resolveRevision, splitRevisionPath } from "~/server/git/refs";
import { withStore } from "~/server/git/store";
import { HttpError, notFoundError } from "~/server/errors";
import { blameFile, BlameUnavailable } from "~/server/code/blame";
import { lastCommitsForDirectory, pathHistory } from "~/server/code/path-history";
import { listAllFiles } from "~/server/code/files";
import { codeIndexStatus, ftsQuery, searchAllCode, searchRepoCode } from "~/server/code/search";
import { ensureCodeIndex } from "~/server/code/search-index";
import { renderNotebook } from "~/server/code/notebook";
import { repoRef } from "~/lib/validation";
import type { CodeSearchHit } from "~/lib/code-intel";
import type { Viewer } from "~/lib/types";

const HTTP_UNPROCESSABLE = 422;
const MAX_NOTEBOOK_BYTES = 5 * 1024 * 1024;
const decoder = new TextDecoder();
const splatInput = repoRef.extend({ splat: z.string().default("") });

async function resolveSplat(owner: string, name: string, splat: string, viewer: Viewer | null) {
  const { repo } = await requireRepoAccess(owner, name, viewer, "read");
  assertRepoReady(repo);
  const refs = await listRefs(repo);
  const resolved = splitRevisionPath(refs, splat);
  if (!resolved) throw notFoundError("Branch or path not found");
  await assertVisibleRevision(repo, resolved.revision);
  return { repo, refs, ...resolved };
}

export const getBlame = createServerFn({ method: "GET" })
  .middleware([viewerMiddleware])
  .validator(splatInput)
  .handler(async ({ data, context }) => {
    await limitHeavy(context.viewer);