fix(provider): type auth errors (#27301)
This commit is contained in:
@@ -10,6 +10,26 @@ import { described } from "./metadata"
|
||||
|
||||
const root = "/provider"
|
||||
|
||||
const ProviderAuthErrorName = Schema.Union([
|
||||
Schema.Literal("BadRequest"),
|
||||
Schema.Literal("ProviderAuthOauthMissing"),
|
||||
Schema.Literal("ProviderAuthOauthCodeMissing"),
|
||||
Schema.Literal("ProviderAuthOauthCallbackFailed"),
|
||||
Schema.Literal("ProviderAuthValidationFailed"),
|
||||
])
|
||||
export class ProviderAuthApiError extends Schema.ErrorClass<ProviderAuthApiError>("ProviderAuthError")(
|
||||
{
|
||||
name: ProviderAuthErrorName,
|
||||
data: Schema.Struct({
|
||||
providerID: Schema.optional(ProviderID),
|
||||
field: Schema.optional(Schema.String),
|
||||
message: Schema.optional(Schema.String),
|
||||
kind: Schema.optional(Schema.String),
|
||||
}),
|
||||
},
|
||||
{ httpApiStatus: 400 },
|
||||
) {}
|
||||
|
||||
export const ProviderApi = HttpApi.make("provider")
|
||||
.add(
|
||||
HttpApiGroup.make("provider")
|
||||
@@ -39,7 +59,7 @@ export const ProviderApi = HttpApi.make("provider")
|
||||
query: WorkspaceRoutingQuery,
|
||||
payload: ProviderAuth.AuthorizeInput,
|
||||
success: described(Schema.UndefinedOr(ProviderAuth.Authorization), "Authorization URL and method"),
|
||||
error: HttpApiError.BadRequest,
|
||||
error: ProviderAuthApiError,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "provider.oauth.authorize",
|
||||
@@ -52,7 +72,7 @@ export const ProviderApi = HttpApi.make("provider")
|
||||
query: WorkspaceRoutingQuery,
|
||||
payload: ProviderAuth.CallbackInput,
|
||||
success: described(Schema.Boolean, "OAuth callback processed successfully"),
|
||||
error: HttpApiError.BadRequest,
|
||||
error: ProviderAuthApiError,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "provider.oauth.callback",
|
||||
|
||||
@@ -6,8 +6,29 @@ 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 { HttpApiBuilder } from "effect/unstable/httpapi"
|
||||
import { InstanceHttpApi } from "../api"
|
||||
import { ProviderAuthApiError } from "../groups/provider"
|
||||
|
||||
function mapProviderAuthError<A, R>(self: Effect.Effect<A, ProviderAuth.Error, R>) {
|
||||
return self.pipe(
|
||||
Effect.mapError((error) => {
|
||||
if (error instanceof ProviderAuth.OauthMissing) {
|
||||
return new ProviderAuthApiError({ name: error._tag, data: { providerID: error.providerID } })
|
||||
}
|
||||
if (error instanceof ProviderAuth.OauthCodeMissing) {
|
||||
return new ProviderAuthApiError({ name: error._tag, data: { providerID: error.providerID } })
|
||||
}
|
||||
if (error instanceof ProviderAuth.OauthCallbackFailed) {
|
||||
return new ProviderAuthApiError({ name: error._tag, data: {} })
|
||||
}
|
||||
if (error instanceof ProviderAuth.ValidationFailed) {
|
||||
return new ProviderAuthApiError({ name: error._tag, data: { field: error.field, message: error.message } })
|
||||
}
|
||||
return new ProviderAuthApiError({ name: "BadRequest", data: {} })
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
@@ -44,13 +65,13 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider"
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.AuthorizeInput
|
||||
}) {
|
||||
return yield* svc
|
||||
.authorize({
|
||||
return yield* mapProviderAuthError(
|
||||
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: {
|
||||
@@ -59,7 +80,7 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider"
|
||||
}) {
|
||||
const body = yield* Effect.orDie(ctx.request.text)
|
||||
const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe(
|
||||
Effect.mapError(() => new HttpApiError.BadRequest({})),
|
||||
Effect.mapError(() => new ProviderAuthApiError({ name: "BadRequest", data: {} })),
|
||||
)
|
||||
// Match legacy route behavior: when authorize() resolves without a
|
||||
// result (e.g. no further redirect), serialize as JSON `null` instead
|
||||
@@ -72,13 +93,13 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider"
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.CallbackInput
|
||||
}) {
|
||||
yield* svc
|
||||
.callback({
|
||||
yield* mapProviderAuthError(
|
||||
svc.callback({
|
||||
providerID: ctx.params.providerID,
|
||||
method: ctx.payload.method,
|
||||
code: ctx.payload.code,
|
||||
})
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
}),
|
||||
)
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect)
|
||||
HttpServerResponse.jsonUnsafe(error.toObject(), {
|
||||
status: iife(() => {
|
||||
if (error instanceof Provider.ModelNotFoundError) return 400
|
||||
if (error.name === "ProviderAuthValidationFailed") return 400
|
||||
return 500
|
||||
}),
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user