44// REF: PR#3 blocking review from skulidropek
55// SOURCE: n/a
66// PURITY: SHELL
7- // EFFECT: Effect<void , never, never> - all errors handled
7+ // EFFECT: Effect<ReadonlyArray<Pet> , never, never> - all errors handled with an empty-list fallback
88
99import { Console , Effect , Match } from "effect"
1010
1111import { type ClientOptions , createClientEffect } from "../src/index.js"
12- import type { Paths } from "../tests/fixtures/petstore.openapi.js"
12+ import type { Components , Paths } from "../tests/fixtures/petstore.openapi.js"
13+
14+ type Pet = Components [ "schemas" ] [ "Pet" ]
15+ type Pets = ReadonlyArray < Pet >
1316
1417const clientOptions : ClientOptions = {
1518 baseUrl : "https://petstore.example.com" ,
@@ -28,28 +31,52 @@ const clientOptions: ClientOptions = {
2831// COMPLEXITY: O(1)
2932const apiClient = createClientEffect < Paths > ( clientOptions )
3033
31- const listPetsProgram = apiClient . GET ( "/pets" , {
34+ const emptyPets : Pets = [ ]
35+
36+ /**
37+ * Converts a handled listPets failure into the list monoid identity.
38+ *
39+ * @param logEffect - Diagnostic shell effect that records the handled failure
40+ * @returns Effect with an empty pets list and no error channel
41+ *
42+ * @pure false - preserves Console logging effect
43+ * @effect never
44+ * @invariant forall handledFailure: recoverWithEmptyPets(handledFailure) = []
45+ * @complexity O(1)
46+ * @throws Never - all failures are represented in the Effect error channel
47+ */
48+ const recoverWithEmptyPets = ( logEffect : Effect . Effect < void > ) : Effect . Effect < Pets > =>
49+ logEffect . pipe ( Effect . as ( emptyPets ) )
50+
51+ const listPetsProgram : Effect . Effect < Pets > = apiClient . GET ( "/pets" , {
3252 params : { query : { limit : 10 } }
3353} ) . pipe (
3454 Effect . flatMap ( ( success ) =>
3555 Match . value ( success ) . pipe (
36- Match . when ( { status : 200 } , ( { body } ) => Console . log ( `Got ${ body . length } pets` ) ) ,
56+ Match . when ( { status : 200 } , ( { body } ) =>
57+ Console . log ( `Got ${ body . length } pets` ) . pipe ( Effect . as ( body ) )
58+ ) ,
3759 Match . exhaustive
3860 )
3961 ) ,
4062 Effect . catchTags ( {
4163 HttpError : ( error ) =>
4264 Match . value ( error . status ) . pipe (
43- Match . when ( 500 , ( ) => Console . log ( `Server error: ${ error . body . message } ` ) ) ,
65+ Match . when ( 500 , ( ) =>
66+ recoverWithEmptyPets ( Console . log ( `Server error: ${ error . body . message } ` ) )
67+ ) ,
4468 Match . exhaustive
4569 ) ,
46- TransportError : ( { error } ) => Console . log ( `Transport error: ${ error . message } ` ) ,
47- UnexpectedStatus : ( { body, status } ) => Console . log ( `Unexpected status ${ status } : ${ body } ` ) ,
70+ TransportError : ( { error } ) => recoverWithEmptyPets ( Console . log ( `Transport error: ${ error . message } ` ) ) ,
71+ UnexpectedStatus : ( { body, status } ) =>
72+ recoverWithEmptyPets ( Console . log ( `Unexpected status ${ status } : ${ body } ` ) ) ,
4873 UnexpectedContentType : ( { actual, expected } ) =>
49- Console . log ( `Unexpected content type ${ actual ?? "unknown" } ; expected ${ expected . join ( ", " ) } ` ) ,
50- ParseError : ( { error } ) => Console . log ( `Parse error: ${ error . message } ` ) ,
51- DecodeError : ( { error } ) => Console . log ( `Decode error: ${ error . message } ` )
74+ recoverWithEmptyPets (
75+ Console . log ( `Unexpected content type ${ actual ?? "unknown" } ; expected ${ expected . join ( ", " ) } ` )
76+ ) ,
77+ ParseError : ( { error } ) => recoverWithEmptyPets ( Console . log ( `Parse error: ${ error . message } ` ) ) ,
78+ DecodeError : ( { error } ) => recoverWithEmptyPets ( Console . log ( `Decode error: ${ error . message } ` ) )
5279 } )
5380)
5481
55- export const strictErrorHandlingProgram : Effect . Effect < void > = listPetsProgram
82+ export const strictErrorHandlingProgram : Effect . Effect < Pets > = listPetsProgram
0 commit comments