1
- import AbortCallback from './abortCallback '
1
+ import AbortPromise from './abortPromise '
2
2
3
3
4
4
type ModifyCallback < Data , ModifiedData = Data > = ( value : Data ) => ModifiedData | PromiseLike < ModifiedData >
@@ -7,8 +7,11 @@ type FirstCallback<Data> = (value: Data) => Data | any
7
7
8
8
type EmptyCallback = ( ) => void
9
9
10
+ type ErrorCallback < Data , ModifiedData = Data > = ( error : Error | any ) => Promise < void > | AbortRequest < Data , ModifiedData >
11
+
10
12
type AbortRequestInit < Data , ModifiedData > = RequestInit & {
11
13
onSuccess : ModifyCallback < Data , ModifiedData >
14
+ onError ?: ErrorCallback < Data , ModifiedData >
12
15
}
13
16
14
17
type PendingRequest = {
@@ -18,19 +21,17 @@ type PendingRequest = {
18
21
19
22
const requestsQueue : Record < string , PendingRequest | undefined > = { }
20
23
21
- const dummyPromise = new Promise ( ( ) => { } )
22
-
23
24
// Returns fetch promise that can be aborted
24
25
// If we create several promises, only one request will be executed
25
26
class AbortRequest < Data , ModifiedData > {
26
27
private controller = new AbortController ( )
27
28
request : Promise < Data >
28
- promise : Promise < ModifiedData >
29
+ promise : AbortPromise < ModifiedData >
29
30
body : string
30
31
isAborted : boolean
31
32
32
33
constructor ( url : RequestInfo | URL , abortRequestInit : AbortRequestInit < Data , ModifiedData > ) {
33
- const { onSuccess, ...init } = abortRequestInit
34
+ const { onSuccess, onError , ...init } = abortRequestInit
34
35
35
36
this . body = init . body as string
36
37
this . isAborted = false
@@ -46,14 +47,34 @@ class AbortRequest<Data, ModifiedData> {
46
47
...init ,
47
48
signal : this . controller . signal ,
48
49
} )
49
- . then ( ( res ) => res . json ( ) )
50
+ . then ( ( response ) => {
51
+ if ( response . ok ) {
52
+ return response . json ( )
53
+ }
54
+
55
+ return response . json ( ) . then ( ( json ) => Promise . reject ( json ) )
56
+ } )
50
57
. then ( ( json ) => {
51
58
requestsQueue [ this . body ] = undefined
59
+
60
+ if ( json ?. errors ) {
61
+ throw new Error ( json . errors [ 0 ] . message )
62
+ }
63
+
64
+ // Subgraph encountered indexing errors at some past block
65
+ if ( json ?. data ?. _meta ?. hasIndexingErrors ) {
66
+ throw new Error ( 'Subgraph indexing error' )
67
+ }
68
+
52
69
return json ?. data as Data
53
70
} )
54
71
. catch ( ( error ) => {
55
72
requestsQueue [ this . body ] = undefined
56
73
74
+ if ( typeof onError === 'function' ) {
75
+ onError ( error )
76
+ }
77
+
57
78
return Promise . reject ( error )
58
79
} )
59
80
@@ -63,42 +84,37 @@ class AbortRequest<Data, ModifiedData> {
63
84
}
64
85
}
65
86
66
- this . promise = this . request
67
- . then ( ( data ) => {
68
- try {
69
- if ( this . isAborted ) {
70
- return dummyPromise as Promise < ModifiedData >
71
- }
72
-
73
- if ( typeof onSuccess === 'function' ) {
74
- return onSuccess ( data ) as Promise < ModifiedData >
75
- }
87
+ this . promise = new AbortPromise < ModifiedData > ( async ( resolve , reject ) => {
88
+ try {
89
+ const result = await this . request
76
90
77
- return data as Promise < ModifiedData >
78
- }
79
- catch ( error ) {
80
- return Promise . reject ( error )
91
+ if ( typeof onSuccess === 'function' ) {
92
+ return resolve ( onSuccess ( result ) as ModifiedData )
81
93
}
82
- } )
83
- . catch ( ( error ) => {
84
- if ( this . isAborted ) {
85
- return dummyPromise as Promise < ModifiedData >
94
+
95
+ return resolve ( result as ModifiedData )
96
+ }
97
+ catch ( error ) {
98
+ if ( typeof onError === 'function' ) {
99
+ // ATTN use resolve because onError can return a promise
100
+ return resolve ( onError ( error ) as ModifiedData )
86
101
}
87
102
88
- return Promise . reject ( error )
89
- } )
103
+ return reject ( error )
104
+ }
105
+ } , this . abort . bind ( this ) )
90
106
}
91
107
92
108
then ( onSuccess : FirstCallback < ModifiedData > , onError ?: FirstCallback < ModifiedData > ) {
93
- return new AbortCallback ( this . promise . then ( onSuccess , onError ) , this . abort . bind ( this ) )
109
+ return this . promise . then ( onSuccess , onError )
94
110
}
95
111
96
112
catch ( callback : FirstCallback < ModifiedData > ) {
97
- return new AbortCallback ( this . promise . catch ( callback ) , this . abort . bind ( this ) )
113
+ return this . promise . catch ( callback )
98
114
}
99
115
100
116
finally ( callback : EmptyCallback ) {
101
- return new AbortCallback ( this . promise . finally ( callback ) , this . abort . bind ( this ) )
117
+ return this . promise . finally ( callback )
102
118
}
103
119
104
120
abort ( ) {
0 commit comments