From dbd48d423d44d6acc8eb494d0763265e59eb219f Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sat, 9 May 2026 00:30:00 -0400 Subject: [PATCH] fix(server): match Hono wire format for authorize undefined and share errors (#26474) --- .../src/server/routes/instance/httpapi/groups/session.ts | 4 ++-- .../server/routes/instance/httpapi/handlers/provider.ts | 6 ++++-- .../server/routes/instance/httpapi/handlers/session.ts | 9 +++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts index 1159c88030..967cc80206 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts @@ -261,7 +261,7 @@ export const SessionApi = HttpApi.make("session") HttpApiEndpoint.post("share", SessionPaths.share, { params: { sessionID: SessionID }, success: described(Session.Info, "Successfully shared session"), - error: [HttpApiError.BadRequest, ApiNotFoundError], + error: [HttpApiError.InternalServerError, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.share", @@ -272,7 +272,7 @@ export const SessionApi = HttpApi.make("session") HttpApiEndpoint.delete("unshare", SessionPaths.share, { params: { sessionID: SessionID }, success: described(Session.Info, "Successfully unshared session"), - error: [HttpApiError.BadRequest, ApiNotFoundError], + error: [HttpApiError.InternalServerError, ApiNotFoundError], }).annotateMerge( OpenApi.annotations({ identifier: "session.unshare", diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts index f9df530a92..15049fcc55 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts @@ -61,9 +61,11 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe( Effect.mapError(() => new HttpApiError.BadRequest({})), ) + // Match legacy Hono 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 }) - if (result === undefined) return HttpServerResponse.empty({ status: 200 }) - return HttpServerResponse.jsonUnsafe(result) + return HttpServerResponse.jsonUnsafe(result ?? null) }) const callback = Effect.fn("ProviderHttpApi.callback")(function* (ctx: { diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index 56fa7adb15..7b60cd1fc3 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -213,13 +213,18 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", return true }) + // share/unshare errors aren't all client-induced — storage and network + // failures from SessionShare are real possibilities. Map to a typed 500 + // (matches the legacy Hono path which routed any failure through + // ErrorMiddleware → NamedError.Unknown 500) instead of blanket-mapping + // every failure to a 400 BadRequest. const share = Effect.fn("SessionHttpApi.share")(function* (ctx: { params: { sessionID: SessionID } }) { - yield* shareSvc.share(ctx.params.sessionID).pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) + yield* shareSvc.share(ctx.params.sessionID).pipe(Effect.mapError(() => new HttpApiError.InternalServerError({}))) return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) }) const unshare = Effect.fn("SessionHttpApi.unshare")(function* (ctx: { params: { sessionID: SessionID } }) { - yield* shareSvc.unshare(ctx.params.sessionID).pipe(Effect.mapError(() => new HttpApiError.BadRequest({}))) + yield* shareSvc.unshare(ctx.params.sessionID).pipe(Effect.mapError(() => new HttpApiError.InternalServerError({}))) return yield* SessionError.mapStorageNotFound(session.get(ctx.params.sessionID)) })