@@ -2,7 +2,7 @@ import { isPlainObject } from "./is-plain-object.js";
2
2
import { RequestError } from "@octokit/request-error" ;
3
3
import type { EndpointInterface } from "@octokit/types" ;
4
4
5
- export default function fetchWrapper (
5
+ export default async function fetchWrapper (
6
6
requestOptions : ReturnType < EndpointInterface > ,
7
7
) {
8
8
const fetch : typeof globalThis . fetch =
@@ -34,121 +34,127 @@ export default function fetchWrapper(
34
34
let status : number ;
35
35
let url : string ;
36
36
37
- return fetch ( requestOptions . url , {
38
- method : requestOptions . method ,
39
- body,
40
- redirect : requestOptions . request ?. redirect ,
41
- // Header values must be `string`
42
- headers : requestHeaders ,
43
- signal : requestOptions . request ?. signal ,
44
- // duplex must be set if request.body is ReadableStream or Async Iterables.
45
- // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex.
46
- ...( requestOptions . body && { duplex : "half" } ) ,
47
- } )
48
- . then ( async ( response ) => {
49
- url = response . url ;
50
- status = response . status ;
51
-
52
- for ( const keyAndValue of response . headers ) {
53
- responseHeaders [ keyAndValue [ 0 ] ] = keyAndValue [ 1 ] ;
54
- }
37
+ let response : Response ;
38
+
39
+ try {
40
+ response = await fetch ( requestOptions . url , {
41
+ method : requestOptions . method ,
42
+ body,
43
+ redirect : requestOptions . request ?. redirect ,
44
+ // Header values must be `string`
45
+ headers : requestHeaders ,
46
+ signal : requestOptions . request ?. signal ,
47
+ // duplex must be set if request.body is ReadableStream or Async Iterables.
48
+ // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex.
49
+ ...( requestOptions . body && { duplex : "half" } ) ,
50
+ } ) ;
51
+ // wrap fetch errors as RequestError if it is not a AbortError
52
+ } catch ( error ) {
53
+ let message = "Unknown Error" ;
54
+ if ( error instanceof Error ) {
55
+ if ( error . name === "AbortError" ) throw error ;
55
56
56
- if ( "deprecation" in responseHeaders ) {
57
- const matches =
58
- responseHeaders . link &&
59
- responseHeaders . link . match ( / < ( [ ^ > ] + ) > ; r e l = " d e p r e c a t i o n " / ) ;
60
- const deprecationLink = matches && matches . pop ( ) ;
61
- log . warn (
62
- `[@octokit/request] "${ requestOptions . method } ${
63
- requestOptions . url
64
- } " is deprecated. It is scheduled to be removed on ${ responseHeaders . sunset } ${
65
- deprecationLink ? `. See ${ deprecationLink } ` : ""
66
- } `,
67
- ) ;
68
- }
57
+ message = error . message ;
69
58
70
- if ( status === 204 || status === 205 ) {
71
- return ;
59
+ // undici throws a TypeError for network errors
60
+ // and puts the error message in `error.cause`
61
+ // https://github.com/nodejs/undici/blob/e5c9d703e63cd5ad691b8ce26e3f9a81c598f2e3/lib/fetch/index.js#L227
62
+ if ( error . name === "TypeError" && "cause" in error ) {
63
+ if ( error . cause instanceof Error ) {
64
+ message = error . cause . message ;
65
+ } else if ( typeof error . cause === "string" ) {
66
+ message = error . cause ;
67
+ }
72
68
}
69
+ }
73
70
74
- // GitHub API returns 200 for HEAD requests
75
- if ( requestOptions . method === "HEAD" ) {
76
- if ( status < 400 ) {
77
- return ;
78
- }
71
+ const requestError = new RequestError ( message , 500 , {
72
+ request : requestOptions ,
73
+ } ) ;
74
+ requestError . cause = error ;
79
75
80
- throw new RequestError ( response . statusText , status , {
81
- response : {
82
- url,
83
- status,
84
- headers : responseHeaders ,
85
- data : undefined ,
86
- } ,
87
- request : requestOptions ,
88
- } ) ;
89
- }
76
+ throw requestError ;
77
+ }
78
+ url = response . url ;
79
+ status = response . status ;
90
80
91
- if ( status === 304 ) {
92
- throw new RequestError ( "Not modified" , status , {
93
- response : {
94
- url,
95
- status,
96
- headers : responseHeaders ,
97
- data : await getResponseData ( response ) ,
98
- } ,
99
- request : requestOptions ,
100
- } ) ;
101
- }
81
+ for ( const keyAndValue of response . headers ) {
82
+ responseHeaders [ keyAndValue [ 0 ] ] = keyAndValue [ 1 ] ;
83
+ }
102
84
103
- if ( status >= 400 ) {
104
- const data = await getResponseData ( response ) ;
85
+ if ( "deprecation" in responseHeaders ) {
86
+ const matches =
87
+ responseHeaders . link &&
88
+ responseHeaders . link . match ( / < ( [ ^ > ] + ) > ; r e l = " d e p r e c a t i o n " / ) ;
89
+ const deprecationLink = matches && matches . pop ( ) ;
90
+ log . warn (
91
+ `[@octokit/request] "${ requestOptions . method } ${
92
+ requestOptions . url
93
+ } " is deprecated. It is scheduled to be removed on ${ responseHeaders . sunset } ${
94
+ deprecationLink ? `. See ${ deprecationLink } ` : ""
95
+ } `,
96
+ ) ;
97
+ }
98
+
99
+ if ( status === 204 || status === 205 ) {
100
+ return ;
101
+ }
105
102
106
- const error = new RequestError ( toErrorMessage ( data ) , status , {
107
- response : {
108
- url,
109
- status,
110
- headers : responseHeaders ,
111
- data,
112
- } ,
113
- request : requestOptions ,
114
- } ) ;
103
+ // GitHub API returns 200 for HEAD requests
104
+ if ( requestOptions . method === "HEAD" ) {
105
+ if ( status < 400 ) {
106
+ return ;
107
+ }
115
108
116
- throw error ;
117
- }
109
+ throw new RequestError ( response . statusText , status , {
110
+ response : {
111
+ url,
112
+ status,
113
+ headers : responseHeaders ,
114
+ data : undefined ,
115
+ } ,
116
+ request : requestOptions ,
117
+ } ) ;
118
+ }
118
119
119
- return parseSuccessResponseBody
120
- ? await getResponseData ( response )
121
- : response . body ;
122
- } )
123
- . then ( ( data ) => {
124
- return {
120
+ if ( status === 304 ) {
121
+ throw new RequestError ( "Not modified" , status , {
122
+ response : {
123
+ url,
125
124
status,
125
+ headers : responseHeaders ,
126
+ data : await getResponseData ( response ) ,
127
+ } ,
128
+ request : requestOptions ,
129
+ } ) ;
130
+ }
131
+
132
+ if ( status >= 400 ) {
133
+ const data = await getResponseData ( response ) ;
134
+
135
+ const error = new RequestError ( toErrorMessage ( data ) , status , {
136
+ response : {
126
137
url,
138
+ status,
127
139
headers : responseHeaders ,
128
140
data,
129
- } ;
130
- } )
131
- . catch ( ( error ) => {
132
- if ( error instanceof RequestError ) throw error ;
133
- else if ( error . name === "AbortError" ) throw error ;
141
+ } ,
142
+ request : requestOptions ,
143
+ } ) ;
134
144
135
- let message = error . message ;
145
+ throw error ;
146
+ }
136
147
137
- // undici throws a TypeError for network errors
138
- // and puts the error message in `error.cause`
139
- // https://github.com/nodejs/undici/blob/e5c9d703e63cd5ad691b8ce26e3f9a81c598f2e3/lib/fetch/index.js#L227
140
- if ( error . name === "TypeError" && "cause" in error ) {
141
- if ( error . cause instanceof Error ) {
142
- message = error . cause . message ;
143
- } else if ( typeof error . cause === "string" ) {
144
- message = error . cause ;
145
- }
146
- }
148
+ const responseBody = parseSuccessResponseBody
149
+ ? await getResponseData ( response )
150
+ : response . body ;
147
151
148
- throw new RequestError ( message , 500 , {
149
- request : requestOptions ,
150
- } ) ;
151
- } ) ;
152
+ return {
153
+ status,
154
+ url,
155
+ headers : responseHeaders ,
156
+ data : responseBody ,
157
+ } ;
152
158
}
153
159
154
160
async function getResponseData ( response : Response ) {
0 commit comments