Skip to content
21 changes: 21 additions & 0 deletions packages/api/src/api/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,29 @@ export type GithubAuthStatus = {
readonly tokens: ReadonlyArray<GithubAuthTokenStatus>
}

export type GitlabAuthTokenStatus = {
readonly key: string
readonly label: string
readonly status: "valid" | "invalid" | "unknown"
readonly login: string | null
}

export type GitlabAuthStatus = {
readonly summary: string
readonly tokens: ReadonlyArray<GitlabAuthTokenStatus>
}

export type GithubAuthLoginRequest = {
readonly label?: string | null | undefined
readonly token?: string | null | undefined
readonly scopes?: string | null | undefined
}

export type GitlabAuthLoginRequest = {
readonly label?: string | null | undefined
readonly token?: string | null | undefined
}

export type AuthMenuFlow =
| "GithubRemove"
| "GitSet"
Expand Down Expand Up @@ -197,6 +214,10 @@ export type GithubAuthLogoutRequest = {
readonly label?: string | null | undefined
}

export type GitlabAuthLogoutRequest = {
readonly label?: string | null | undefined
}

export type CodexAuthImportRequest = {
readonly label?: string | null | undefined
readonly authText: string
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/api/errors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Data } from "effect"

export class ApiAuthRequiredError extends Data.TaggedError("ApiAuthRequiredError")<{
readonly provider: "github"
readonly provider: "github" | "gitlab"
readonly message: string
readonly command: string
}> {}
Expand Down
11 changes: 11 additions & 0 deletions packages/api/src/api/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export const GithubAuthLoginRequestSchema = Schema.Struct({
scopes: OptionalNullableString
})

export const GitlabAuthLoginRequestSchema = Schema.Struct({
label: OptionalNullableString,
token: OptionalNullableString
})

export const AuthMenuFlowSchema = Schema.Literal(
"GithubRemove",
"GitSet",
Expand Down Expand Up @@ -74,6 +79,10 @@ export const GithubAuthLogoutRequestSchema = Schema.Struct({
label: OptionalNullableString
})

export const GitlabAuthLogoutRequestSchema = Schema.Struct({
label: OptionalNullableString
})

export const CodexAuthImportRequestSchema = Schema.Struct({
label: OptionalNullableString,
authText: Schema.String
Expand Down Expand Up @@ -282,9 +291,11 @@ export const TerminalSessionSchema = Schema.Struct({

export type CreateProjectRequestInput = Schema.Schema.Type<typeof CreateProjectRequestSchema>
export type GithubAuthLoginRequestInput = Schema.Schema.Type<typeof GithubAuthLoginRequestSchema>
export type GitlabAuthLoginRequestInput = Schema.Schema.Type<typeof GitlabAuthLoginRequestSchema>
export type AuthMenuRequestInput = Schema.Schema.Type<typeof AuthMenuRequestSchema>
export type AuthTerminalSessionRequestInput = Schema.Schema.Type<typeof AuthTerminalSessionRequestSchema>
export type GithubAuthLogoutRequestInput = Schema.Schema.Type<typeof GithubAuthLogoutRequestSchema>
export type GitlabAuthLogoutRequestInput = Schema.Schema.Type<typeof GitlabAuthLogoutRequestSchema>
export type CodexAuthImportRequestInput = Schema.Schema.Type<typeof CodexAuthImportRequestSchema>
export type CodexAuthLoginRequestInput = Schema.Schema.Type<typeof CodexAuthLoginRequestSchema>
export type CodexAuthLogoutRequestInput = Schema.Schema.Type<typeof CodexAuthLogoutRequestSchema>
Expand Down
45 changes: 45 additions & 0 deletions packages/api/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import {
CreateProjectRequestSchema,
ExchangePollRequestSchema,
ExchangeSubscribeRequestSchema,
GitlabAuthLoginRequestSchema,
GitlabAuthLogoutRequestSchema,
GithubAuthLoginRequestSchema,
GithubAuthLogoutRequestSchema,
ProjectDatabaseProfileRequestSchema,
Expand All @@ -40,13 +42,17 @@ import { defaultProjectsRoot } from "@effect-template/lib/usecases/menu-helpers"
import { resolveWorkspaceRoot } from "@effect-template/lib/shell/workspace-root"
import {
importCodexAuth,
loginGitlabAuth,
loginGithubAuth,
logoutCodexAuth,
logoutGitlabAuth,
logoutGithubAuth,
readCodexAuthStatus,
readGitlabAuthStatus,
readGithubAuthStatus,
} from "./services/auth.js"
import { readAuthMenuSnapshot, runAuthMenuFlow } from "./services/auth-menu.js"
import { streamGitlabAuthLogin } from "./services/auth-gitlab-login-stream.js"
import { streamGithubAuthLogin } from "./services/auth-github-login-stream.js"
import { createAuthTerminalSession, deleteAuthTerminalSession } from "./services/auth-terminal-sessions.js"
import { streamCodexAuthLogin } from "./services/auth-codex-login-stream.js"
Expand Down Expand Up @@ -352,6 +358,8 @@ const readCreateProjectRequest = () => HttpServerRequest.schemaBodyJson(CreatePr
const readCreateFollowRequest = () => HttpServerRequest.schemaBodyJson(CreateFollowRequestSchema)
const readGithubAuthLoginRequest = () => HttpServerRequest.schemaBodyJson(GithubAuthLoginRequestSchema)
const readGithubAuthLogoutRequest = () => HttpServerRequest.schemaBodyJson(GithubAuthLogoutRequestSchema)
const readGitlabAuthLoginRequest = () => HttpServerRequest.schemaBodyJson(GitlabAuthLoginRequestSchema)
const readGitlabAuthLogoutRequest = () => HttpServerRequest.schemaBodyJson(GitlabAuthLogoutRequestSchema)
const readAuthMenuRequest = () => HttpServerRequest.schemaBodyJson(AuthMenuRequestSchema)
const readAuthTerminalSessionRequest = () => HttpServerRequest.schemaBodyJson(AuthTerminalSessionRequestSchema)
const readCodexAuthImportRequest = () => HttpServerRequest.schemaBodyJson(CodexAuthImportRequestSchema)
Expand Down Expand Up @@ -502,6 +510,13 @@ export const makeRouter = () => {
return yield* _(jsonResponse({ status }, 200))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.get(
"/auth/gitlab/status",
Effect.gen(function*(_) {
const status = yield* _(readGitlabAuthStatus())
return yield* _(jsonResponse({ status }, 200))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.get(
"/auth/menu",
Effect.gen(function*(_) {
Expand Down Expand Up @@ -531,6 +546,28 @@ export const makeRouter = () => {
return yield* _(jsonResponse({ ok: true, status }, 201))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.post(
"/auth/gitlab/login/stream",
Effect.gen(function*(_) {
const request = yield* _(readGitlabAuthLoginRequest())
const outputStream = yield* _(streamGitlabAuthLogin(request))
return HttpServerResponse.stream(outputStream, {
status: 200,
headers: {
"content-type": "text/plain; charset=utf-8",
"cache-control": "no-cache"
}
})
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.post(
"/auth/gitlab/login",
Effect.gen(function*(_) {
const request = yield* _(readGitlabAuthLoginRequest())
const status = yield* _(loginGitlabAuth(request))
return yield* _(jsonResponse({ ok: true, status }, 201))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.post(
"/auth/menu",
Effect.gen(function*(_) {
Expand Down Expand Up @@ -575,6 +612,14 @@ export const makeRouter = () => {
return yield* _(jsonResponse({ ok: true, status }, 200))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.post(
"/auth/gitlab/logout",
Effect.gen(function*(_) {
const request = yield* _(readGitlabAuthLogoutRequest())
const status = yield* _(logoutGitlabAuth(request))
return yield* _(jsonResponse({ ok: true, status }, 200))
}).pipe(Effect.catchAll(errorResponse))
),
HttpRouter.get(
"/auth/codex/status",
Effect.gen(function*(_) {
Expand Down
Loading