92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
import { ProviderAuth } from "@/provider/auth"
|
|
import { Config } from "@/config/config"
|
|
import { ModelsDev } from "@/provider/models"
|
|
import { Provider } from "@/provider/provider"
|
|
import { ProviderID } from "@/provider/schema"
|
|
import { mapValues } from "remeda"
|
|
import { Effect, Schema } from "effect"
|
|
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
|
import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
|
|
import { InstanceHttpApi } from "../api"
|
|
|
|
export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider", (handlers) =>
|
|
Effect.gen(function* () {
|
|
const cfg = yield* Config.Service
|
|
const provider = yield* Provider.Service
|
|
const svc = yield* ProviderAuth.Service
|
|
|
|
const list = Effect.fn("ProviderHttpApi.list")(function* () {
|
|
const config = yield* cfg.get()
|
|
const all = yield* ModelsDev.Service.use((s) => s.get())
|
|
const disabled = new Set(config.disabled_providers ?? [])
|
|
const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
|
|
const filtered: Record<string, (typeof all)[string]> = {}
|
|
for (const [key, value] of Object.entries(all)) {
|
|
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) filtered[key] = value
|
|
}
|
|
const connected = yield* provider.list()
|
|
const providers = Object.assign(
|
|
mapValues(filtered, (item) => Provider.fromModelsDevProvider(item)),
|
|
connected,
|
|
)
|
|
return {
|
|
all: Object.values(providers).map(Provider.toPublicInfo),
|
|
default: Provider.defaultModelIDs(providers),
|
|
connected: Object.keys(connected),
|
|
}
|
|
})
|
|
|
|
const auth = Effect.fn("ProviderHttpApi.auth")(function* () {
|
|
return yield* svc.methods()
|
|
})
|
|
|
|
const authorize = Effect.fn("ProviderHttpApi.authorize")(function* (ctx: {
|
|
params: { providerID: ProviderID }
|
|
payload: ProviderAuth.AuthorizeInput
|
|
}) {
|
|
return yield* svc
|
|
.authorize({
|
|
providerID: ctx.params.providerID,
|
|
method: ctx.payload.method,
|
|
inputs: ctx.payload.inputs,
|
|
})
|
|
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
|
})
|
|
|
|
const authorizeRaw = Effect.fn("ProviderHttpApi.authorizeRaw")(function* (ctx: {
|
|
params: { providerID: ProviderID }
|
|
request: HttpServerRequest.HttpServerRequest
|
|
}) {
|
|
const body = yield* Effect.orDie(ctx.request.text)
|
|
const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe(
|
|
Effect.mapError(() => new HttpApiError.BadRequest({})),
|
|
)
|
|
// Match legacy route behavior: when authorize() resolves without a
|
|
// result (e.g. no further redirect), serialize as JSON `null` instead
|
|
// of an empty body so clients can `.json()` parse the response.
|
|
const result = yield* authorize({ params: ctx.params, payload })
|
|
return HttpServerResponse.jsonUnsafe(result ?? null)
|
|
})
|
|
|
|
const callback = Effect.fn("ProviderHttpApi.callback")(function* (ctx: {
|
|
params: { providerID: ProviderID }
|
|
payload: ProviderAuth.CallbackInput
|
|
}) {
|
|
yield* svc
|
|
.callback({
|
|
providerID: ctx.params.providerID,
|
|
method: ctx.payload.method,
|
|
code: ctx.payload.code,
|
|
})
|
|
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
|
return true
|
|
})
|
|
|
|
return handlers
|
|
.handle("list", list)
|
|
.handle("auth", auth)
|
|
.handleRaw("authorize", authorizeRaw)
|
|
.handle("callback", callback)
|
|
}),
|
|
)
|