Repository navigation
Expand file tree
/
Copy pathfiles.ts
More file actions
36 lines (34 loc) · 1.53 KB
/
Copy pathfiles.ts
File metadata and controls
36 lines (34 loc) · 1.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { listRepoFiles, readRepoFile } from "@procni/core";
import { ProcniError } from "@procni/shared";
import type { FastifyInstance } from "fastify";
import type { ServerDeps } from "../types.js";
/**
* Backs the file-search compose flow: a developer searches for a file by
* name, then reads its content client-side to highlight and select lines
* from — no diff or existing opportunity involved. Both routes trust
* `listRepoFiles`/`readRepoFile`'s `git ls-files` allowlist as the only
* path-safety check; see `packages/core/src/git/files.ts`.
*/
export async function filesRoute(app: FastifyInstance, deps: ServerDeps): Promise<void> {
app.get("/api/v1/files", async (request) => {
const query = (request.query as { q?: string }).q ?? "";
const files = await listRepoFiles(deps.repoRoot);
const matches = query ? files.filter((path) => path.toLowerCase().includes(query.toLowerCase())) : files;
return { files: matches.slice(0, 50) };
});
app.get("/api/v1/files/content", async (request, reply) => {
const path = (request.query as { path?: string }).path;
if (!path) {
return reply.code(400).send({ error: { code: "SCHEMA_VALIDATION_FAILED", message: "path is required." } });
}
try {
const content = await readRepoFile(deps.repoRoot, path);
return { content };
} catch (error) {
if (error instanceof ProcniError && error.code === "NOT_FOUND") {
return reply.code(404).send({ error: { code: "NOT_FOUND", message: error.message } });
}
throw error;
}
});
}