1+ import { PrismaClient , RepoIndexingJobType } from '@sourcebot/db' ;
2+ import { createLogger } from '@sourcebot/shared' ;
3+ import express , { Request , Response } from 'express' ;
4+ import 'express-async-errors' ;
5+ import * as http from "http" ;
6+ import z from 'zod' ;
7+ import { ConnectionManager } from './connectionManager.js' ;
8+ import { PromClient } from './promClient.js' ;
9+ import { RepoIndexManager } from './repoIndexManager.js' ;
10+
11+ const logger = createLogger ( 'api' ) ;
12+ const PORT = 3060 ;
13+
14+ export class Api {
15+ private server : http . Server ;
16+
17+ constructor (
18+ promClient : PromClient ,
19+ private prisma : PrismaClient ,
20+ private connectionManager : ConnectionManager ,
21+ private repoIndexManager : RepoIndexManager ,
22+ ) {
23+ const app = express ( ) ;
24+ app . use ( express . json ( ) ) ;
25+ app . use ( express . urlencoded ( { extended : true } ) ) ;
26+
27+ // Prometheus metrics endpoint
28+ app . use ( '/metrics' , async ( _req : Request , res : Response ) => {
29+ res . set ( 'Content-Type' , promClient . registry . contentType ) ;
30+ const metrics = await promClient . registry . metrics ( ) ;
31+ res . end ( metrics ) ;
32+ } ) ;
33+
34+ app . post ( '/api/sync-connection' , this . syncConnection . bind ( this ) ) ;
35+ app . post ( '/api/index-repo' , this . indexRepo . bind ( this ) ) ;
36+
37+ this . server = app . listen ( PORT , ( ) => {
38+ logger . info ( `API server is running on port ${ PORT } ` ) ;
39+ } ) ;
40+ }
41+
42+ private async syncConnection ( req : Request , res : Response ) {
43+ const schema = z . object ( {
44+ connectionId : z . number ( ) ,
45+ } ) . strict ( ) ;
46+
47+ const parsed = schema . safeParse ( req . body ) ;
48+ if ( ! parsed . success ) {
49+ res . status ( 400 ) . json ( { error : parsed . error . message } ) ;
50+ return ;
51+ }
52+
53+ const { connectionId } = parsed . data ;
54+ const connection = await this . prisma . connection . findUnique ( {
55+ where : {
56+ id : connectionId ,
57+ }
58+ } ) ;
59+
60+ if ( ! connection ) {
61+ res . status ( 404 ) . json ( { error : 'Connection not found' } ) ;
62+ return ;
63+ }
64+
65+ const [ jobId ] = await this . connectionManager . createJobs ( [ connection ] ) ;
66+
67+ res . status ( 200 ) . json ( { jobId } ) ;
68+ }
69+
70+ private async indexRepo ( req : Request , res : Response ) {
71+ const schema = z . object ( {
72+ repoId : z . number ( ) ,
73+ } ) . strict ( ) ;
74+
75+ const parsed = schema . safeParse ( req . body ) ;
76+ if ( ! parsed . success ) {
77+ res . status ( 400 ) . json ( { error : parsed . error . message } ) ;
78+ return ;
79+ }
80+
81+ const { repoId } = parsed . data ;
82+ const repo = await this . prisma . repo . findUnique ( {
83+ where : { id : repoId } ,
84+ } ) ;
85+
86+ if ( ! repo ) {
87+ res . status ( 404 ) . json ( { error : 'Repo not found' } ) ;
88+ return ;
89+ }
90+
91+ const [ jobId ] = await this . repoIndexManager . createJobs ( [ repo ] , RepoIndexingJobType . INDEX ) ;
92+ res . status ( 200 ) . json ( { jobId } ) ;
93+ }
94+
95+ public async dispose ( ) {
96+ return new Promise < void > ( ( resolve , reject ) => {
97+ this . server . close ( ( err ) => {
98+ if ( err ) reject ( err ) ;
99+ else resolve ( undefined ) ;
100+ } ) ;
101+ } ) ;
102+ }
103+ }
0 commit comments