11import { Cache , Clock , Duration , Effect , Layer , Option , Schema , SchemaGetter , ServiceMap } from "effect"
2- import { FetchHttpClient , HttpClient , HttpClientRequest , HttpClientResponse } from "effect/unstable/http"
2+ import { FetchHttpClient , HttpClient , HttpClientError , HttpClientRequest , HttpClientResponse } from "effect/unstable/http"
33
44import { makeRuntime } from "@/effect/run-service"
55import { withTransientReadRetry } from "@/util/effect-http-client"
66import { AccountRepo , type AccountRow } from "./repo"
7+ import { normalizeServerUrl } from "./url"
78import {
89 type AccountError ,
910 AccessToken ,
@@ -12,6 +13,7 @@ import {
1213 Info ,
1314 RefreshToken ,
1415 AccountServiceError ,
16+ AccountTransportError ,
1517 Login ,
1618 Org ,
1719 OrgID ,
@@ -30,6 +32,7 @@ export {
3032 type AccountError ,
3133 AccountRepoError ,
3234 AccountServiceError ,
35+ AccountTransportError ,
3336 AccessToken ,
3437 RefreshToken ,
3538 DeviceCode ,
@@ -132,13 +135,30 @@ const isTokenFresh = (tokenExpiry: number | null, now: number) =>
132135
133136const mapAccountServiceError =
134137 ( message = "Account service operation failed" ) =>
135- < A , E , R > ( effect : Effect . Effect < A , E , R > ) : Effect . Effect < A , AccountServiceError , R > =>
138+ < A , E , R > ( effect : Effect . Effect < A , E , R > ) : Effect . Effect < A , AccountError , R > =>
136139 effect . pipe (
137- Effect . mapError ( ( cause ) =>
138- cause instanceof AccountServiceError ? cause : new AccountServiceError ( { message, cause } ) ,
139- ) ,
140+ Effect . mapError ( ( cause ) => accountErrorFromCause ( cause , message ) ) ,
140141 )
141142
143+ const accountErrorFromCause = ( cause : unknown , message : string ) : AccountError => {
144+ if ( cause instanceof AccountServiceError || cause instanceof AccountTransportError ) {
145+ return cause
146+ }
147+
148+ if ( HttpClientError . isHttpClientError ( cause ) ) {
149+ switch ( cause . reason . _tag ) {
150+ case "TransportError" : {
151+ return AccountTransportError . fromHttpClientError ( cause . reason )
152+ }
153+ default : {
154+ return new AccountServiceError ( { message, cause } )
155+ }
156+ }
157+ }
158+
159+ return new AccountServiceError ( { message, cause } )
160+ }
161+
142162export namespace Account {
143163 export interface Interface {
144164 readonly active : ( ) => Effect . Effect < Option . Option < Info > , AccountError >
@@ -346,8 +366,9 @@ export namespace Account {
346366 } )
347367
348368 const login = Effect . fn ( "Account.login" ) ( function * ( server : string ) {
369+ const normalizedServer = normalizeServerUrl ( server )
349370 const response = yield * executeEffectOk (
350- HttpClientRequest . post ( `${ server } /auth/device/code` ) . pipe (
371+ HttpClientRequest . post ( `${ normalizedServer } /auth/device/code` ) . pipe (
351372 HttpClientRequest . acceptJson ,
352373 HttpClientRequest . schemaBodyJson ( ClientId ) ( new ClientId ( { client_id : clientId } ) ) ,
353374 ) ,
@@ -359,8 +380,8 @@ export namespace Account {
359380 return new Login ( {
360381 code : parsed . device_code ,
361382 user : parsed . user_code ,
362- url : `${ server } ${ parsed . verification_uri_complete } ` ,
363- server,
383+ url : `${ normalizedServer } ${ parsed . verification_uri_complete } ` ,
384+ server : normalizedServer ,
364385 expiry : parsed . expires_in ,
365386 interval : parsed . interval ,
366387 } )
0 commit comments