fix(opencode): improve console login transport errors (#21350)

This commit is contained in:
Kit Langton
2026-04-07 18:31:53 +00:00
committed by GitHub
parent 81bdffc81c
commit d83fe4b540
8 changed files with 182 additions and 13 deletions
@@ -56,6 +56,32 @@ it.live("persistAccount inserts and getRow retrieves", () =>
}),
)
it.live("persistAccount normalizes trailing slashes in stored server URLs", () =>
Effect.gen(function* () {
const id = AccountID.make("user-1")
yield* AccountRepo.use((r) =>
r.persistAccount({
id,
email: "test@example.com",
url: "https://control.example.com/",
accessToken: AccessToken.make("at_123"),
refreshToken: RefreshToken.make("rt_456"),
expiry: Date.now() + 3600_000,
orgID: Option.none(),
}),
)
const row = yield* AccountRepo.use((r) => r.getRow(id))
const active = yield* AccountRepo.use((r) => r.active())
const list = yield* AccountRepo.use((r) => r.list())
expect(Option.getOrThrow(row).url).toBe("https://control.example.com")
expect(Option.getOrThrow(active).url).toBe("https://control.example.com")
expect(list[0]?.url).toBe("https://control.example.com")
}),
)
it.live("persistAccount sets the active account and org", () =>
Effect.gen(function* () {
const id1 = AccountID.make("user-1")
+63 -2
View File
@@ -1,10 +1,20 @@
import { expect } from "bun:test"
import { Duration, Effect, Layer, Option, Schema } from "effect"
import { HttpClient, HttpClientResponse } from "effect/unstable/http"
import { HttpClient, HttpClientError, HttpClientResponse } from "effect/unstable/http"
import { AccountRepo } from "../../src/account/repo"
import { Account } from "../../src/account"
import { AccessToken, AccountID, DeviceCode, Login, Org, OrgID, RefreshToken, UserCode } from "../../src/account/schema"
import {
AccessToken,
AccountID,
AccountTransportError,
DeviceCode,
Login,
Org,
OrgID,
RefreshToken,
UserCode,
} from "../../src/account/schema"
import { Database } from "../../src/storage/db"
import { testEffect } from "../lib/effect"
@@ -57,6 +67,57 @@ const deviceTokenClient = (body: unknown, status = 400) =>
const poll = (body: unknown, status = 400) =>
Account.Service.use((s) => s.poll(login())).pipe(Effect.provide(live(deviceTokenClient(body, status))))
it.live("login normalizes trailing slashes in the provided server URL", () =>
Effect.gen(function* () {
const seen: Array<string> = []
const client = HttpClient.make((req) =>
Effect.gen(function* () {
seen.push(`${req.method} ${req.url}`)
if (req.url === "https://one.example.com/auth/device/code") {
return json(req, {
device_code: "device-code",
user_code: "user-code",
verification_uri_complete: "/device?user_code=user-code",
expires_in: 600,
interval: 5,
})
}
return json(req, {}, 404)
}),
)
const result = yield* Account.Service.use((s) => s.login("https://one.example.com/")).pipe(Effect.provide(live(client)))
expect(seen).toEqual(["POST https://one.example.com/auth/device/code"])
expect(result.server).toBe("https://one.example.com")
expect(result.url).toBe("https://one.example.com/device?user_code=user-code")
}),
)
it.live("login maps transport failures to account transport errors", () =>
Effect.gen(function* () {
const client = HttpClient.make((req) =>
Effect.fail(
new HttpClientError.HttpClientError({
reason: new HttpClientError.TransportError({ request: req }),
}),
),
)
const error = yield* Effect.flip(
Account.Service.use((s) => s.login("https://one.example.com")).pipe(Effect.provide(live(client))),
)
expect(error).toBeInstanceOf(AccountTransportError)
if (error instanceof AccountTransportError) {
expect(error.method).toBe("POST")
expect(error.url).toBe("https://one.example.com/auth/device/code")
}
}),
)
it.live("orgsByAccount groups orgs per account", () =>
Effect.gen(function* () {
yield* AccountRepo.use((r) =>
+18
View File
@@ -0,0 +1,18 @@
import { describe, expect, test } from "bun:test"
import { AccountTransportError } from "../../src/account/schema"
import { FormatError } from "../../src/cli/error"
describe("cli.error", () => {
test("formats account transport errors clearly", () => {
const error = new AccountTransportError({
method: "POST",
url: "https://console.opencode.ai/auth/device/code",
})
const formatted = FormatError(error)
expect(formatted).toContain("Could not reach POST https://console.opencode.ai/auth/device/code.")
expect(formatted).toContain("This failed before the server returned an HTTP response.")
expect(formatted).toContain("Check your network, proxy, or VPN configuration and try again.")
})
})