@@ -9,9 +9,10 @@ import * as HttpServerError from "@effect/platform/HttpServerError"
99import * as ParseResult from "effect/ParseResult"
1010import * as Schema from "effect/Schema"
1111
12- import { ApiBadRequestError , ApiConflictError , ApiInternalError , ApiNotFoundError , describeUnknown } from "./api/errors.js"
13- import { CreateAgentRequestSchema , CreateFollowRequestSchema , CreateProjectRequestSchema } from "./api/schema.js"
12+ import { ApiAuthRequiredError , ApiBadRequestError , ApiConflictError , ApiInternalError , ApiNotFoundError , describeUnknown } from "./api/errors.js"
13+ import { ApplyAllRequestSchema , CreateAgentRequestSchema , CreateFollowRequestSchema , CreateProjectRequestSchema , GithubAuthLoginRequestSchema , GithubAuthLogoutRequestSchema } from "./api/schema.js"
1414import { uiHtml , uiScript , uiStyles } from "./ui.js"
15+ import { loginGithubAuth , logoutGithubAuth , readGithubAuthStatus } from "./services/auth.js"
1516import { getAgent , getAgentAttachInfo , listAgents , readAgentLogs , startAgent , stopAgent } from "./services/agents.js"
1617import { latestProjectCursor , listProjectEventsSince } from "./services/events.js"
1718import {
@@ -27,8 +28,10 @@ import {
2728 makeFederationOutboxCollection
2829} from "./services/federation.js"
2930import {
31+ applyAllProjects ,
3032 createProjectFromRequest ,
3133 deleteProjectById ,
34+ downAllProjects ,
3235 downProject ,
3336 getProject ,
3437 listProjects ,
@@ -48,6 +51,7 @@ const AgentParamsSchema = Schema.Struct({
4851} )
4952
5053type ApiError =
54+ | ApiAuthRequiredError
5155 | ApiBadRequestError
5256 | ApiNotFoundError
5357 | ApiConflictError
@@ -93,6 +97,20 @@ const errorResponse = (error: ApiError | unknown) => {
9397 return jsonResponse ( { error : { type : error . _tag , message : error . message , details : error . details } } , 400 )
9498 }
9599
100+ if ( error instanceof ApiAuthRequiredError ) {
101+ return jsonResponse (
102+ {
103+ error : {
104+ type : error . _tag ,
105+ message : error . message ,
106+ provider : error . provider ,
107+ command : error . command
108+ }
109+ } ,
110+ 401
111+ )
112+ }
113+
96114 if ( error instanceof ApiNotFoundError ) {
97115 return jsonResponse ( { error : { type : error . _tag , message : error . message } } , 404 )
98116 }
@@ -121,6 +139,9 @@ const agentParams = HttpRouter.schemaParams(AgentParamsSchema)
121139
122140const readCreateProjectRequest = ( ) => HttpServerRequest . schemaBodyJson ( CreateProjectRequestSchema )
123141const readCreateFollowRequest = ( ) => HttpServerRequest . schemaBodyJson ( CreateFollowRequestSchema )
142+ const readGithubAuthLoginRequest = ( ) => HttpServerRequest . schemaBodyJson ( GithubAuthLoginRequestSchema )
143+ const readGithubAuthLogoutRequest = ( ) => HttpServerRequest . schemaBodyJson ( GithubAuthLogoutRequestSchema )
144+ const readApplyAllRequest = ( ) => HttpServerRequest . schemaBodyJson ( ApplyAllRequestSchema )
124145const readInboxPayload = ( ) => HttpServerRequest . schemaBodyJson ( Schema . Unknown )
125146
126147const configuredFederationPublicOrigin =
@@ -184,6 +205,29 @@ export const makeRouter = () => {
184205 HttpRouter . get ( "/ui/styles.css" , textResponse ( uiStyles , "text/css; charset=utf-8" , 200 ) ) ,
185206 HttpRouter . get ( "/ui/app.js" , textResponse ( uiScript , "application/javascript; charset=utf-8" , 200 ) ) ,
186207 HttpRouter . get ( "/health" , jsonResponse ( { ok : true } , 200 ) ) ,
208+ HttpRouter . get (
209+ "/auth/github/status" ,
210+ Effect . gen ( function * ( _ ) {
211+ const status = yield * _ ( readGithubAuthStatus ( ) )
212+ return yield * _ ( jsonResponse ( { status } , 200 ) )
213+ } ) . pipe ( Effect . catchAll ( errorResponse ) )
214+ ) ,
215+ HttpRouter . post (
216+ "/auth/github/login" ,
217+ Effect . gen ( function * ( _ ) {
218+ const request = yield * _ ( readGithubAuthLoginRequest ( ) )
219+ const status = yield * _ ( loginGithubAuth ( request ) )
220+ return yield * _ ( jsonResponse ( { ok : true , status } , 201 ) )
221+ } ) . pipe ( Effect . catchAll ( errorResponse ) )
222+ ) ,
223+ HttpRouter . post (
224+ "/auth/github/logout" ,
225+ Effect . gen ( function * ( _ ) {
226+ const request = yield * _ ( readGithubAuthLogoutRequest ( ) )
227+ const status = yield * _ ( logoutGithubAuth ( request ) )
228+ return yield * _ ( jsonResponse ( { ok : true , status } , 200 ) )
229+ } ) . pipe ( Effect . catchAll ( errorResponse ) )
230+ ) ,
187231 HttpRouter . get (
188232 "/federation/issues" ,
189233 Effect . sync ( ( ) => ( { issues : listFederationIssues ( ) } ) ) . pipe (
@@ -274,6 +318,21 @@ export const makeRouter = () => {
274318 return yield * _ ( jsonResponse ( { project } , 201 ) )
275319 } ) . pipe ( Effect . catchAll ( errorResponse ) )
276320 ) ,
321+ HttpRouter . post (
322+ "/projects/apply-all" ,
323+ Effect . gen ( function * ( _ ) {
324+ const request = yield * _ ( readApplyAllRequest ( ) )
325+ yield * _ ( applyAllProjects ( request . activeOnly ?? false ) )
326+ return yield * _ ( jsonResponse ( { ok : true } , 200 ) )
327+ } ) . pipe ( Effect . catchAll ( errorResponse ) )
328+ ) ,
329+ HttpRouter . post (
330+ "/projects/down-all" ,
331+ downAllProjects ( ) . pipe (
332+ Effect . flatMap ( ( ) => jsonResponse ( { ok : true } , 200 ) ) ,
333+ Effect . catchAll ( errorResponse )
334+ )
335+ ) ,
277336 HttpRouter . get (
278337 "/projects/:projectId" ,
279338 projectParams . pipe (
0 commit comments