1
- import { UsageError } from 'clipanion ' ;
2
- import { once } from 'events ' ;
3
- import type { RequestOptions } from 'https ' ;
4
- import type { IncomingMessage , ClientRequest } from 'http ' ;
5
- import { stderr , stdin } from 'process ' ;
1
+ import assert from 'assert ' ;
2
+ import { UsageError } from 'clipanion ' ;
3
+ import { once } from 'events ' ;
4
+ import { stderr , stdin } from 'process ' ;
5
+ import { Readable } from 'stream ' ;
6
6
7
- export async function fetchUrlStream ( url : string , options : RequestOptions = { } ) {
7
+ export async function fetch ( input : string | URL , init ?: RequestInit ) {
8
8
if ( process . env . COREPACK_ENABLE_NETWORK === `0` )
9
- throw new UsageError ( `Network access disabled by the environment; can't reach ${ url } ` ) ;
9
+ throw new UsageError ( `Network access disabled by the environment; can't reach ${ input } ` ) ;
10
10
11
- const { default : https } = await import ( `https` ) ;
12
-
13
- const { ProxyAgent} = await import ( `proxy-agent` ) ;
14
-
15
- const proxyAgent = new ProxyAgent ( ) ;
11
+ const agent = await getProxyAgent ( input ) ;
16
12
17
13
if ( process . env . COREPACK_ENABLE_DOWNLOAD_PROMPT === `1` ) {
18
- console . error ( `Corepack is about to download ${ url } .` ) ;
14
+ console . error ( `Corepack is about to download ${ input } .` ) ;
19
15
if ( stdin . isTTY && ! process . env . CI ) {
20
16
stderr . write ( `\nDo you want to continue? [Y/n] ` ) ;
21
17
stdin . resume ( ) ;
@@ -30,60 +26,55 @@ export async function fetchUrlStream(url: string, options: RequestOptions = {})
30
26
}
31
27
}
32
28
33
- return new Promise < IncomingMessage > ( ( resolve , reject ) => {
34
- const createRequest = ( url : string ) => {
35
- const request : ClientRequest = https . get ( url , { ...options , agent : proxyAgent } , response => {
36
- const statusCode = response . statusCode ;
37
-
38
- if ( [ 301 , 302 , 307 , 308 ] . includes ( statusCode as number ) && response . headers . location )
39
- return createRequest ( response . headers . location as string ) ;
40
-
41
- if ( statusCode != null && statusCode >= 200 && statusCode < 300 )
42
- return resolve ( response ) ;
43
-
44
- return reject ( new Error ( `Server answered with HTTP ${ statusCode } when performing the request to ${ url } ; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting` ) ) ;
45
- } ) ;
29
+ let response ;
30
+ try {
31
+ response = await globalThis . fetch ( input , {
32
+ ...init ,
33
+ dispatcher : agent ,
34
+ } ) ;
35
+ } catch ( error ) {
36
+ throw new Error (
37
+ `Error when performing the request to ${ input } ; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting` ,
38
+ { cause : error } ,
39
+ ) ;
40
+ }
46
41
47
- request . on ( `error` , err => {
48
- reject ( new Error ( `Error when performing the request to ${ url } ; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting` ) ) ;
49
- } ) ;
50
- } ;
42
+ if ( ! response . ok ) {
43
+ await response . arrayBuffer ( ) ;
44
+ throw new Error (
45
+ `Server answered with HTTP ${ response . status } when performing the request to ${ input } ; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting` ,
46
+ ) ;
47
+ }
51
48
52
- createRequest ( url ) ;
53
- } ) ;
49
+ return response ;
54
50
}
55
51
56
- export async function fetchAsBuffer ( url : string , options ?: RequestOptions ) {
57
- const response = await fetchUrlStream ( url , options ) ;
58
-
59
- return new Promise < Buffer > ( ( resolve , reject ) => {
60
- const chunks : Array < Buffer > = [ ] ;
52
+ export async function fetchAsJson ( input : string | URL , init ?: RequestInit ) {
53
+ const response = await fetch ( input , init ) ;
54
+ return response . json ( ) as Promise < any > ;
55
+ }
61
56
62
- response . on ( `data` , chunk => {
63
- chunks . push ( chunk ) ;
64
- } ) ;
57
+ export async function fetchUrlStream ( input : string | URL , init ?: RequestInit ) {
58
+ const response = await fetch ( input , init ) ;
59
+ const webStream = response . body ;
60
+ assert ( webStream , `Expected stream to be set` ) ;
61
+ const stream = Readable . fromWeb ( webStream ) ;
62
+ return stream ;
63
+ }
65
64
66
- response . on ( `error` , error => {
67
- reject ( error ) ;
68
- } ) ;
65
+ async function getProxyAgent ( input : string | URL ) {
66
+ const { getProxyForUrl} = await import ( `proxy-from-env` ) ;
69
67
70
- response . on ( `end` , ( ) => {
71
- resolve ( Buffer . concat ( chunks ) ) ;
72
- } ) ;
73
- } ) ;
74
- }
68
+ // @ts -expect-error - The internal implementation is compatible with a WHATWG URL instance
69
+ const proxy = getProxyForUrl ( input ) ;
75
70
76
- export async function fetchAsJson ( url : string , options ?: RequestOptions ) {
77
- const buffer = await fetchAsBuffer ( url , options ) ;
78
- const asText = buffer . toString ( ) ;
71
+ if ( ! proxy ) return undefined ;
79
72
80
- try {
81
- return JSON . parse ( asText ) ;
82
- } catch ( error ) {
83
- const truncated = asText . length > 30
84
- ? `${ asText . slice ( 0 , 30 ) } ...`
85
- : asText ;
73
+ // Doing a deep import here since undici isn't tree-shakeable
74
+ const { default : ProxyAgent } = ( await import (
75
+ // @ts -expect-error No types for this specific file
76
+ `undici/lib/proxy-agent.js`
77
+ ) ) as { default : typeof import ( 'undici' ) . ProxyAgent } ;
86
78
87
- throw new Error ( `Couldn't parse JSON data: ${ JSON . stringify ( truncated ) } ` ) ;
88
- }
79
+ return new ProxyAgent ( proxy ) ;
89
80
}
0 commit comments