isomorphic-git 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +7 -0
- package/README.md +384 -0
- package/browser-tests.json +8 -0
- package/cli.cjs +41 -0
- package/http/node/index.cjs +230 -0
- package/http/node/index.d.ts +77 -0
- package/http/node/index.js +224 -0
- package/http/node/package.json +6 -0
- package/http/web/index.cjs +170 -0
- package/http/web/index.d.ts +77 -0
- package/http/web/index.js +166 -0
- package/http/web/index.umd.js +176 -0
- package/http/web/package.json +7 -0
- package/index.cjs +14249 -0
- package/index.d.ts +4262 -0
- package/index.js +14178 -0
- package/index.umd.min.d.ts +4262 -0
- package/index.umd.min.js +9 -0
- package/index.umd.min.js.map +1 -0
- package/package.json +155 -0
- package/size_report.html +64 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
+
|
|
7
|
+
var get = _interopDefault(require('simple-get'));
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {Object} GitProgressEvent
|
|
11
|
+
* @property {string} phase
|
|
12
|
+
* @property {number} loaded
|
|
13
|
+
* @property {number} total
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @callback ProgressCallback
|
|
18
|
+
* @param {GitProgressEvent} progress
|
|
19
|
+
* @returns {void | Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} GitHttpRequest
|
|
24
|
+
* @property {string} url - The URL to request
|
|
25
|
+
* @property {string} [method='GET'] - The HTTP method to use
|
|
26
|
+
* @property {Object<string, string>} [headers={}] - Headers to include in the HTTP request
|
|
27
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of POST requests
|
|
28
|
+
* @property {ProgressCallback} [onProgress] - Reserved for future use (emitting `GitProgressEvent`s)
|
|
29
|
+
* @property {object} [signal] - Reserved for future use (canceling a request)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {Object} GitHttpResponse
|
|
34
|
+
* @property {string} url - The final URL that was fetched after any redirects
|
|
35
|
+
* @property {string} [method] - The HTTP method that was used
|
|
36
|
+
* @property {Object<string, string>} [headers] - HTTP response headers
|
|
37
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of the response
|
|
38
|
+
* @property {number} statusCode - The HTTP status code
|
|
39
|
+
* @property {string} statusMessage - The HTTP status message
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @callback HttpFetch
|
|
44
|
+
* @param {GitHttpRequest} request
|
|
45
|
+
* @returns {Promise<GitHttpResponse>}
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {Object} HttpClient
|
|
50
|
+
* @property {HttpFetch} request
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
// Convert a value to an Async Iterator
|
|
54
|
+
// This will be easier with async generator functions.
|
|
55
|
+
function fromValue(value) {
|
|
56
|
+
let queue = [value];
|
|
57
|
+
return {
|
|
58
|
+
next() {
|
|
59
|
+
return Promise.resolve({ done: queue.length === 0, value: queue.pop() })
|
|
60
|
+
},
|
|
61
|
+
return() {
|
|
62
|
+
queue = [];
|
|
63
|
+
return {}
|
|
64
|
+
},
|
|
65
|
+
[Symbol.asyncIterator]() {
|
|
66
|
+
return this
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getIterator(iterable) {
|
|
72
|
+
if (iterable[Symbol.asyncIterator]) {
|
|
73
|
+
return iterable[Symbol.asyncIterator]()
|
|
74
|
+
}
|
|
75
|
+
if (iterable[Symbol.iterator]) {
|
|
76
|
+
return iterable[Symbol.iterator]()
|
|
77
|
+
}
|
|
78
|
+
if (iterable.next) {
|
|
79
|
+
return iterable
|
|
80
|
+
}
|
|
81
|
+
return fromValue(iterable)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Currently 'for await' upsets my linters.
|
|
85
|
+
async function forAwait(iterable, cb) {
|
|
86
|
+
const iter = getIterator(iterable);
|
|
87
|
+
while (true) {
|
|
88
|
+
const { value, done } = await iter.next();
|
|
89
|
+
if (value) await cb(value);
|
|
90
|
+
if (done) break
|
|
91
|
+
}
|
|
92
|
+
if (iter.return) iter.return();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function asyncIteratorToStream(iter) {
|
|
96
|
+
const { PassThrough } = require('readable-stream');
|
|
97
|
+
const stream = new PassThrough();
|
|
98
|
+
setTimeout(async () => {
|
|
99
|
+
await forAwait(iter, chunk => stream.write(chunk));
|
|
100
|
+
stream.end();
|
|
101
|
+
}, 1);
|
|
102
|
+
return stream
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function collect(iterable) {
|
|
106
|
+
let size = 0;
|
|
107
|
+
const buffers = [];
|
|
108
|
+
// This will be easier once `for await ... of` loops are available.
|
|
109
|
+
await forAwait(iterable, value => {
|
|
110
|
+
buffers.push(value);
|
|
111
|
+
size += value.byteLength;
|
|
112
|
+
});
|
|
113
|
+
const result = new Uint8Array(size);
|
|
114
|
+
let nextIndex = 0;
|
|
115
|
+
for (const buffer of buffers) {
|
|
116
|
+
result.set(buffer, nextIndex);
|
|
117
|
+
nextIndex += buffer.byteLength;
|
|
118
|
+
}
|
|
119
|
+
return result
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Convert a Node stream to an Async Iterator
|
|
123
|
+
function fromNodeStream(stream) {
|
|
124
|
+
// Use native async iteration if it's available.
|
|
125
|
+
const asyncIterator = Object.getOwnPropertyDescriptor(
|
|
126
|
+
stream,
|
|
127
|
+
Symbol.asyncIterator
|
|
128
|
+
);
|
|
129
|
+
if (asyncIterator && asyncIterator.enumerable) {
|
|
130
|
+
return stream
|
|
131
|
+
}
|
|
132
|
+
// Author's Note
|
|
133
|
+
// I tried many MANY ways to do this.
|
|
134
|
+
// I tried two npm modules (stream-to-async-iterator and streams-to-async-iterator) with no luck.
|
|
135
|
+
// I tried using 'readable' and .read(), and .pause() and .resume()
|
|
136
|
+
// It took me two loooong evenings to get to this point.
|
|
137
|
+
// So if you are horrified that this solution just builds up a queue with no backpressure,
|
|
138
|
+
// and turns Promises inside out, too bad. This is the first code that worked reliably.
|
|
139
|
+
let ended = false;
|
|
140
|
+
const queue = [];
|
|
141
|
+
let defer = {};
|
|
142
|
+
stream.on('data', chunk => {
|
|
143
|
+
queue.push(chunk);
|
|
144
|
+
if (defer.resolve) {
|
|
145
|
+
defer.resolve({ value: queue.shift(), done: false });
|
|
146
|
+
defer = {};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
stream.on('error', err => {
|
|
150
|
+
if (defer.reject) {
|
|
151
|
+
defer.reject(err);
|
|
152
|
+
defer = {};
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
stream.on('end', () => {
|
|
156
|
+
ended = true;
|
|
157
|
+
if (defer.resolve) {
|
|
158
|
+
defer.resolve({ done: true });
|
|
159
|
+
defer = {};
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
next() {
|
|
164
|
+
return new Promise((resolve, reject) => {
|
|
165
|
+
if (queue.length === 0 && ended) {
|
|
166
|
+
return resolve({ done: true })
|
|
167
|
+
} else if (queue.length > 0) {
|
|
168
|
+
return resolve({ value: queue.shift(), done: false })
|
|
169
|
+
} else if (queue.length === 0 && !ended) {
|
|
170
|
+
defer = { resolve, reject };
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
},
|
|
174
|
+
return() {
|
|
175
|
+
stream.removeAllListeners();
|
|
176
|
+
if (stream.destroy) stream.destroy();
|
|
177
|
+
},
|
|
178
|
+
[Symbol.asyncIterator]() {
|
|
179
|
+
return this
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* HttpClient
|
|
186
|
+
*
|
|
187
|
+
* @param {GitHttpRequest} request
|
|
188
|
+
* @returns {Promise<GitHttpResponse>}
|
|
189
|
+
*/
|
|
190
|
+
async function request({
|
|
191
|
+
onProgress,
|
|
192
|
+
url,
|
|
193
|
+
method = 'GET',
|
|
194
|
+
headers = {},
|
|
195
|
+
body,
|
|
196
|
+
}) {
|
|
197
|
+
// If we can, we should send it as a single buffer so it sets a Content-Length header.
|
|
198
|
+
if (body && Array.isArray(body)) {
|
|
199
|
+
body = Buffer.from(await collect(body));
|
|
200
|
+
} else if (body) {
|
|
201
|
+
body = asyncIteratorToStream(body);
|
|
202
|
+
}
|
|
203
|
+
return new Promise((resolve, reject) => {
|
|
204
|
+
get(
|
|
205
|
+
{
|
|
206
|
+
url,
|
|
207
|
+
method,
|
|
208
|
+
headers,
|
|
209
|
+
body,
|
|
210
|
+
},
|
|
211
|
+
(err, res) => {
|
|
212
|
+
if (err) return reject(err)
|
|
213
|
+
const iter = fromNodeStream(res);
|
|
214
|
+
resolve({
|
|
215
|
+
url: res.url,
|
|
216
|
+
method: res.method,
|
|
217
|
+
statusCode: res.statusCode,
|
|
218
|
+
statusMessage: res.statusMessage,
|
|
219
|
+
body: iter,
|
|
220
|
+
headers: res.headers,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var index = { request };
|
|
228
|
+
|
|
229
|
+
exports.default = index;
|
|
230
|
+
exports.request = request;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export default index;
|
|
2
|
+
export type GitProgressEvent = {
|
|
3
|
+
phase: string;
|
|
4
|
+
loaded: number;
|
|
5
|
+
total: number;
|
|
6
|
+
};
|
|
7
|
+
export type ProgressCallback = (progress: GitProgressEvent) => void | Promise<void>;
|
|
8
|
+
export type GitHttpRequest = {
|
|
9
|
+
/**
|
|
10
|
+
* - The URL to request
|
|
11
|
+
*/
|
|
12
|
+
url: string;
|
|
13
|
+
/**
|
|
14
|
+
* - The HTTP method to use
|
|
15
|
+
*/
|
|
16
|
+
method?: string;
|
|
17
|
+
/**
|
|
18
|
+
* - Headers to include in the HTTP request
|
|
19
|
+
*/
|
|
20
|
+
headers?: {
|
|
21
|
+
[x: string]: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* - An async iterator of Uint8Arrays that make up the body of POST requests
|
|
25
|
+
*/
|
|
26
|
+
body?: any;
|
|
27
|
+
/**
|
|
28
|
+
* - Reserved for future use (emitting `GitProgressEvent`s)
|
|
29
|
+
*/
|
|
30
|
+
onProgress?: ProgressCallback;
|
|
31
|
+
/**
|
|
32
|
+
* - Reserved for future use (canceling a request)
|
|
33
|
+
*/
|
|
34
|
+
signal?: any;
|
|
35
|
+
};
|
|
36
|
+
export type GitHttpResponse = {
|
|
37
|
+
/**
|
|
38
|
+
* - The final URL that was fetched after any redirects
|
|
39
|
+
*/
|
|
40
|
+
url: string;
|
|
41
|
+
/**
|
|
42
|
+
* - The HTTP method that was used
|
|
43
|
+
*/
|
|
44
|
+
method?: string;
|
|
45
|
+
/**
|
|
46
|
+
* - HTTP response headers
|
|
47
|
+
*/
|
|
48
|
+
headers?: {
|
|
49
|
+
[x: string]: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* - An async iterator of Uint8Arrays that make up the body of the response
|
|
53
|
+
*/
|
|
54
|
+
body?: any;
|
|
55
|
+
/**
|
|
56
|
+
* - The HTTP status code
|
|
57
|
+
*/
|
|
58
|
+
statusCode: number;
|
|
59
|
+
/**
|
|
60
|
+
* - The HTTP status message
|
|
61
|
+
*/
|
|
62
|
+
statusMessage: string;
|
|
63
|
+
};
|
|
64
|
+
export type HttpFetch = (request: GitHttpRequest) => Promise<GitHttpResponse>;
|
|
65
|
+
export type HttpClient = {
|
|
66
|
+
request: HttpFetch;
|
|
67
|
+
};
|
|
68
|
+
declare namespace index {
|
|
69
|
+
export { request };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* HttpClient
|
|
73
|
+
*
|
|
74
|
+
* @param {GitHttpRequest} request
|
|
75
|
+
* @returns {Promise<GitHttpResponse>}
|
|
76
|
+
*/
|
|
77
|
+
export function request({ onProgress, url, method, headers, body, }: GitHttpRequest): Promise<GitHttpResponse>;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import get from 'simple-get';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} GitProgressEvent
|
|
5
|
+
* @property {string} phase
|
|
6
|
+
* @property {number} loaded
|
|
7
|
+
* @property {number} total
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @callback ProgressCallback
|
|
12
|
+
* @param {GitProgressEvent} progress
|
|
13
|
+
* @returns {void | Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} GitHttpRequest
|
|
18
|
+
* @property {string} url - The URL to request
|
|
19
|
+
* @property {string} [method='GET'] - The HTTP method to use
|
|
20
|
+
* @property {Object<string, string>} [headers={}] - Headers to include in the HTTP request
|
|
21
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of POST requests
|
|
22
|
+
* @property {ProgressCallback} [onProgress] - Reserved for future use (emitting `GitProgressEvent`s)
|
|
23
|
+
* @property {object} [signal] - Reserved for future use (canceling a request)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} GitHttpResponse
|
|
28
|
+
* @property {string} url - The final URL that was fetched after any redirects
|
|
29
|
+
* @property {string} [method] - The HTTP method that was used
|
|
30
|
+
* @property {Object<string, string>} [headers] - HTTP response headers
|
|
31
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of the response
|
|
32
|
+
* @property {number} statusCode - The HTTP status code
|
|
33
|
+
* @property {string} statusMessage - The HTTP status message
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @callback HttpFetch
|
|
38
|
+
* @param {GitHttpRequest} request
|
|
39
|
+
* @returns {Promise<GitHttpResponse>}
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {Object} HttpClient
|
|
44
|
+
* @property {HttpFetch} request
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
// Convert a value to an Async Iterator
|
|
48
|
+
// This will be easier with async generator functions.
|
|
49
|
+
function fromValue(value) {
|
|
50
|
+
let queue = [value];
|
|
51
|
+
return {
|
|
52
|
+
next() {
|
|
53
|
+
return Promise.resolve({ done: queue.length === 0, value: queue.pop() })
|
|
54
|
+
},
|
|
55
|
+
return() {
|
|
56
|
+
queue = [];
|
|
57
|
+
return {}
|
|
58
|
+
},
|
|
59
|
+
[Symbol.asyncIterator]() {
|
|
60
|
+
return this
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getIterator(iterable) {
|
|
66
|
+
if (iterable[Symbol.asyncIterator]) {
|
|
67
|
+
return iterable[Symbol.asyncIterator]()
|
|
68
|
+
}
|
|
69
|
+
if (iterable[Symbol.iterator]) {
|
|
70
|
+
return iterable[Symbol.iterator]()
|
|
71
|
+
}
|
|
72
|
+
if (iterable.next) {
|
|
73
|
+
return iterable
|
|
74
|
+
}
|
|
75
|
+
return fromValue(iterable)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Currently 'for await' upsets my linters.
|
|
79
|
+
async function forAwait(iterable, cb) {
|
|
80
|
+
const iter = getIterator(iterable);
|
|
81
|
+
while (true) {
|
|
82
|
+
const { value, done } = await iter.next();
|
|
83
|
+
if (value) await cb(value);
|
|
84
|
+
if (done) break
|
|
85
|
+
}
|
|
86
|
+
if (iter.return) iter.return();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function asyncIteratorToStream(iter) {
|
|
90
|
+
const { PassThrough } = require('readable-stream');
|
|
91
|
+
const stream = new PassThrough();
|
|
92
|
+
setTimeout(async () => {
|
|
93
|
+
await forAwait(iter, chunk => stream.write(chunk));
|
|
94
|
+
stream.end();
|
|
95
|
+
}, 1);
|
|
96
|
+
return stream
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function collect(iterable) {
|
|
100
|
+
let size = 0;
|
|
101
|
+
const buffers = [];
|
|
102
|
+
// This will be easier once `for await ... of` loops are available.
|
|
103
|
+
await forAwait(iterable, value => {
|
|
104
|
+
buffers.push(value);
|
|
105
|
+
size += value.byteLength;
|
|
106
|
+
});
|
|
107
|
+
const result = new Uint8Array(size);
|
|
108
|
+
let nextIndex = 0;
|
|
109
|
+
for (const buffer of buffers) {
|
|
110
|
+
result.set(buffer, nextIndex);
|
|
111
|
+
nextIndex += buffer.byteLength;
|
|
112
|
+
}
|
|
113
|
+
return result
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Convert a Node stream to an Async Iterator
|
|
117
|
+
function fromNodeStream(stream) {
|
|
118
|
+
// Use native async iteration if it's available.
|
|
119
|
+
const asyncIterator = Object.getOwnPropertyDescriptor(
|
|
120
|
+
stream,
|
|
121
|
+
Symbol.asyncIterator
|
|
122
|
+
);
|
|
123
|
+
if (asyncIterator && asyncIterator.enumerable) {
|
|
124
|
+
return stream
|
|
125
|
+
}
|
|
126
|
+
// Author's Note
|
|
127
|
+
// I tried many MANY ways to do this.
|
|
128
|
+
// I tried two npm modules (stream-to-async-iterator and streams-to-async-iterator) with no luck.
|
|
129
|
+
// I tried using 'readable' and .read(), and .pause() and .resume()
|
|
130
|
+
// It took me two loooong evenings to get to this point.
|
|
131
|
+
// So if you are horrified that this solution just builds up a queue with no backpressure,
|
|
132
|
+
// and turns Promises inside out, too bad. This is the first code that worked reliably.
|
|
133
|
+
let ended = false;
|
|
134
|
+
const queue = [];
|
|
135
|
+
let defer = {};
|
|
136
|
+
stream.on('data', chunk => {
|
|
137
|
+
queue.push(chunk);
|
|
138
|
+
if (defer.resolve) {
|
|
139
|
+
defer.resolve({ value: queue.shift(), done: false });
|
|
140
|
+
defer = {};
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
stream.on('error', err => {
|
|
144
|
+
if (defer.reject) {
|
|
145
|
+
defer.reject(err);
|
|
146
|
+
defer = {};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
stream.on('end', () => {
|
|
150
|
+
ended = true;
|
|
151
|
+
if (defer.resolve) {
|
|
152
|
+
defer.resolve({ done: true });
|
|
153
|
+
defer = {};
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
next() {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
if (queue.length === 0 && ended) {
|
|
160
|
+
return resolve({ done: true })
|
|
161
|
+
} else if (queue.length > 0) {
|
|
162
|
+
return resolve({ value: queue.shift(), done: false })
|
|
163
|
+
} else if (queue.length === 0 && !ended) {
|
|
164
|
+
defer = { resolve, reject };
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
},
|
|
168
|
+
return() {
|
|
169
|
+
stream.removeAllListeners();
|
|
170
|
+
if (stream.destroy) stream.destroy();
|
|
171
|
+
},
|
|
172
|
+
[Symbol.asyncIterator]() {
|
|
173
|
+
return this
|
|
174
|
+
},
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* HttpClient
|
|
180
|
+
*
|
|
181
|
+
* @param {GitHttpRequest} request
|
|
182
|
+
* @returns {Promise<GitHttpResponse>}
|
|
183
|
+
*/
|
|
184
|
+
async function request({
|
|
185
|
+
onProgress,
|
|
186
|
+
url,
|
|
187
|
+
method = 'GET',
|
|
188
|
+
headers = {},
|
|
189
|
+
body,
|
|
190
|
+
}) {
|
|
191
|
+
// If we can, we should send it as a single buffer so it sets a Content-Length header.
|
|
192
|
+
if (body && Array.isArray(body)) {
|
|
193
|
+
body = Buffer.from(await collect(body));
|
|
194
|
+
} else if (body) {
|
|
195
|
+
body = asyncIteratorToStream(body);
|
|
196
|
+
}
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
get(
|
|
199
|
+
{
|
|
200
|
+
url,
|
|
201
|
+
method,
|
|
202
|
+
headers,
|
|
203
|
+
body,
|
|
204
|
+
},
|
|
205
|
+
(err, res) => {
|
|
206
|
+
if (err) return reject(err)
|
|
207
|
+
const iter = fromNodeStream(res);
|
|
208
|
+
resolve({
|
|
209
|
+
url: res.url,
|
|
210
|
+
method: res.method,
|
|
211
|
+
statusCode: res.statusCode,
|
|
212
|
+
statusMessage: res.statusMessage,
|
|
213
|
+
body: iter,
|
|
214
|
+
headers: res.headers,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
var index = { request };
|
|
222
|
+
|
|
223
|
+
export default index;
|
|
224
|
+
export { request };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} GitProgressEvent
|
|
7
|
+
* @property {string} phase
|
|
8
|
+
* @property {number} loaded
|
|
9
|
+
* @property {number} total
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @callback ProgressCallback
|
|
14
|
+
* @param {GitProgressEvent} progress
|
|
15
|
+
* @returns {void | Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {Object} GitHttpRequest
|
|
20
|
+
* @property {string} url - The URL to request
|
|
21
|
+
* @property {string} [method='GET'] - The HTTP method to use
|
|
22
|
+
* @property {Object<string, string>} [headers={}] - Headers to include in the HTTP request
|
|
23
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of POST requests
|
|
24
|
+
* @property {ProgressCallback} [onProgress] - Reserved for future use (emitting `GitProgressEvent`s)
|
|
25
|
+
* @property {object} [signal] - Reserved for future use (canceling a request)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {Object} GitHttpResponse
|
|
30
|
+
* @property {string} url - The final URL that was fetched after any redirects
|
|
31
|
+
* @property {string} [method] - The HTTP method that was used
|
|
32
|
+
* @property {Object<string, string>} [headers] - HTTP response headers
|
|
33
|
+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of the response
|
|
34
|
+
* @property {number} statusCode - The HTTP status code
|
|
35
|
+
* @property {string} statusMessage - The HTTP status message
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @callback HttpFetch
|
|
40
|
+
* @param {GitHttpRequest} request
|
|
41
|
+
* @returns {Promise<GitHttpResponse>}
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {Object} HttpClient
|
|
46
|
+
* @property {HttpFetch} request
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
// Convert a value to an Async Iterator
|
|
50
|
+
// This will be easier with async generator functions.
|
|
51
|
+
function fromValue(value) {
|
|
52
|
+
let queue = [value];
|
|
53
|
+
return {
|
|
54
|
+
next() {
|
|
55
|
+
return Promise.resolve({ done: queue.length === 0, value: queue.pop() })
|
|
56
|
+
},
|
|
57
|
+
return() {
|
|
58
|
+
queue = [];
|
|
59
|
+
return {}
|
|
60
|
+
},
|
|
61
|
+
[Symbol.asyncIterator]() {
|
|
62
|
+
return this
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getIterator(iterable) {
|
|
68
|
+
if (iterable[Symbol.asyncIterator]) {
|
|
69
|
+
return iterable[Symbol.asyncIterator]()
|
|
70
|
+
}
|
|
71
|
+
if (iterable[Symbol.iterator]) {
|
|
72
|
+
return iterable[Symbol.iterator]()
|
|
73
|
+
}
|
|
74
|
+
if (iterable.next) {
|
|
75
|
+
return iterable
|
|
76
|
+
}
|
|
77
|
+
return fromValue(iterable)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Currently 'for await' upsets my linters.
|
|
81
|
+
async function forAwait(iterable, cb) {
|
|
82
|
+
const iter = getIterator(iterable);
|
|
83
|
+
while (true) {
|
|
84
|
+
const { value, done } = await iter.next();
|
|
85
|
+
if (value) await cb(value);
|
|
86
|
+
if (done) break
|
|
87
|
+
}
|
|
88
|
+
if (iter.return) iter.return();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function collect(iterable) {
|
|
92
|
+
let size = 0;
|
|
93
|
+
const buffers = [];
|
|
94
|
+
// This will be easier once `for await ... of` loops are available.
|
|
95
|
+
await forAwait(iterable, value => {
|
|
96
|
+
buffers.push(value);
|
|
97
|
+
size += value.byteLength;
|
|
98
|
+
});
|
|
99
|
+
const result = new Uint8Array(size);
|
|
100
|
+
let nextIndex = 0;
|
|
101
|
+
for (const buffer of buffers) {
|
|
102
|
+
result.set(buffer, nextIndex);
|
|
103
|
+
nextIndex += buffer.byteLength;
|
|
104
|
+
}
|
|
105
|
+
return result
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Convert a web ReadableStream (not Node stream!) to an Async Iterator
|
|
109
|
+
// adapted from https://jakearchibald.com/2017/async-iterators-and-generators/
|
|
110
|
+
function fromStream(stream) {
|
|
111
|
+
// Use native async iteration if it's available.
|
|
112
|
+
if (stream[Symbol.asyncIterator]) return stream
|
|
113
|
+
const reader = stream.getReader();
|
|
114
|
+
return {
|
|
115
|
+
next() {
|
|
116
|
+
return reader.read()
|
|
117
|
+
},
|
|
118
|
+
return() {
|
|
119
|
+
reader.releaseLock();
|
|
120
|
+
return {}
|
|
121
|
+
},
|
|
122
|
+
[Symbol.asyncIterator]() {
|
|
123
|
+
return this
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* eslint-env browser */
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* HttpClient
|
|
132
|
+
*
|
|
133
|
+
* @param {GitHttpRequest} request
|
|
134
|
+
* @returns {Promise<GitHttpResponse>}
|
|
135
|
+
*/
|
|
136
|
+
async function request({
|
|
137
|
+
onProgress,
|
|
138
|
+
url,
|
|
139
|
+
method = 'GET',
|
|
140
|
+
headers = {},
|
|
141
|
+
body,
|
|
142
|
+
}) {
|
|
143
|
+
// streaming uploads aren't possible yet in the browser
|
|
144
|
+
if (body) {
|
|
145
|
+
body = await collect(body);
|
|
146
|
+
}
|
|
147
|
+
const res = await fetch(url, { method, headers, body });
|
|
148
|
+
const iter =
|
|
149
|
+
res.body && res.body.getReader
|
|
150
|
+
? fromStream(res.body)
|
|
151
|
+
: [new Uint8Array(await res.arrayBuffer())];
|
|
152
|
+
// convert Header object to ordinary JSON
|
|
153
|
+
headers = {};
|
|
154
|
+
for (const [key, value] of res.headers.entries()) {
|
|
155
|
+
headers[key] = value;
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
url: res.url,
|
|
159
|
+
method: res.method,
|
|
160
|
+
statusCode: res.status,
|
|
161
|
+
statusMessage: res.statusText,
|
|
162
|
+
body: iter,
|
|
163
|
+
headers: headers,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
var index = { request };
|
|
168
|
+
|
|
169
|
+
exports.default = index;
|
|
170
|
+
exports.request = request;
|