Skip to content

Commit 6445267

Browse files
committed
chore: dist
1 parent 85bde9d commit 6445267

20 files changed

+53279
-15
lines changed

.gitignore

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,6 @@
22
/__tests__/__fixtures__/.superblock.txt
33
/__tests__/__fixtures__/index.json
44

5-
# Dist
6-
/http
7-
/index.cjs
8-
/index.d.ts
9-
/index.js
10-
/index.umd.min.js
11-
/index.umd.min.d.ts
12-
/index.umd.min.js.map
13-
/internal-apis.js
14-
/internal-apis.d.ts
15-
/internal-apis.cjs
16-
/internal-apis.umd.min.js
17-
/internal-apis.umd.min.js.map
18-
/dist
19-
205
# Test run artifacts
216
/coverage
227
/junit

http/node/index.cjs

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
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 {Object} [agent] - An HTTP or HTTPS agent that manages connections for the HTTP client (Node.js only)
28+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of POST requests
29+
* @property {ProgressCallback} [onProgress] - Reserved for future use (emitting `GitProgressEvent`s)
30+
* @property {object} [signal] - Reserved for future use (canceling a request)
31+
*/
32+
33+
/**
34+
* @typedef {Object} GitHttpResponse
35+
* @property {string} url - The final URL that was fetched after any redirects
36+
* @property {string} [method] - The HTTP method that was used
37+
* @property {Object<string, string>} [headers] - HTTP response headers
38+
* @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of the response
39+
* @property {number} statusCode - The HTTP status code
40+
* @property {string} statusMessage - The HTTP status message
41+
*/
42+
43+
/**
44+
* @callback HttpFetch
45+
* @param {GitHttpRequest} request
46+
* @returns {Promise<GitHttpResponse>}
47+
*/
48+
49+
/**
50+
* @typedef {Object} HttpClient
51+
* @property {HttpFetch} request
52+
*/
53+
54+
// Convert a value to an Async Iterator
55+
// This will be easier with async generator functions.
56+
function fromValue(value) {
57+
let queue = [value];
58+
return {
59+
next() {
60+
return Promise.resolve({ done: queue.length === 0, value: queue.pop() })
61+
},
62+
return() {
63+
queue = [];
64+
return {}
65+
},
66+
[Symbol.asyncIterator]() {
67+
return this
68+
},
69+
}
70+
}
71+
72+
function getIterator(iterable) {
73+
if (iterable[Symbol.asyncIterator]) {
74+
return iterable[Symbol.asyncIterator]()
75+
}
76+
if (iterable[Symbol.iterator]) {
77+
return iterable[Symbol.iterator]()
78+
}
79+
if (iterable.next) {
80+
return iterable
81+
}
82+
return fromValue(iterable)
83+
}
84+
85+
// Currently 'for await' upsets my linters.
86+
async function forAwait(iterable, cb) {
87+
const iter = getIterator(iterable);
88+
while (true) {
89+
const { value, done } = await iter.next();
90+
if (value) await cb(value);
91+
if (done) break
92+
}
93+
if (iter.return) iter.return();
94+
}
95+
96+
function asyncIteratorToStream(iter) {
97+
const { PassThrough } = require('readable-stream');
98+
const stream = new PassThrough();
99+
setTimeout(async () => {
100+
await forAwait(iter, chunk => stream.write(chunk));
101+
stream.end();
102+
}, 1);
103+
return stream
104+
}
105+
106+
async function collect(iterable) {
107+
let size = 0;
108+
const buffers = [];
109+
// This will be easier once `for await ... of` loops are available.
110+
await forAwait(iterable, value => {
111+
buffers.push(value);
112+
size += value.byteLength;
113+
});
114+
const result = new Uint8Array(size);
115+
let nextIndex = 0;
116+
for (const buffer of buffers) {
117+
result.set(buffer, nextIndex);
118+
nextIndex += buffer.byteLength;
119+
}
120+
return result
121+
}
122+
123+
// Convert a Node stream to an Async Iterator
124+
function fromNodeStream(stream) {
125+
// Use native async iteration if it's available.
126+
const asyncIterator = Object.getOwnPropertyDescriptor(
127+
stream,
128+
Symbol.asyncIterator
129+
);
130+
if (asyncIterator && asyncIterator.enumerable) {
131+
return stream
132+
}
133+
// Author's Note
134+
// I tried many MANY ways to do this.
135+
// I tried two npm modules (stream-to-async-iterator and streams-to-async-iterator) with no luck.
136+
// I tried using 'readable' and .read(), and .pause() and .resume()
137+
// It took me two loooong evenings to get to this point.
138+
// So if you are horrified that this solution just builds up a queue with no backpressure,
139+
// and turns Promises inside out, too bad. This is the first code that worked reliably.
140+
let ended = false;
141+
const queue = [];
142+
let defer = {};
143+
stream.on('data', chunk => {
144+
queue.push(chunk);
145+
if (defer.resolve) {
146+
defer.resolve({ value: queue.shift(), done: false });
147+
defer = {};
148+
}
149+
});
150+
stream.on('error', err => {
151+
if (defer.reject) {
152+
defer.reject(err);
153+
defer = {};
154+
}
155+
});
156+
stream.on('end', () => {
157+
ended = true;
158+
if (defer.resolve) {
159+
defer.resolve({ done: true });
160+
defer = {};
161+
}
162+
});
163+
return {
164+
next() {
165+
return new Promise((resolve, reject) => {
166+
if (queue.length === 0 && ended) {
167+
return resolve({ done: true })
168+
} else if (queue.length > 0) {
169+
return resolve({ value: queue.shift(), done: false })
170+
} else if (queue.length === 0 && !ended) {
171+
defer = { resolve, reject };
172+
}
173+
})
174+
},
175+
return() {
176+
stream.removeAllListeners();
177+
if (stream.destroy) stream.destroy();
178+
},
179+
[Symbol.asyncIterator]() {
180+
return this
181+
},
182+
}
183+
}
184+
185+
/**
186+
* HttpClient
187+
*
188+
* @param {GitHttpRequest} request
189+
* @returns {Promise<GitHttpResponse>}
190+
*/
191+
async function request({
192+
onProgress,
193+
url,
194+
method = 'GET',
195+
headers = {},
196+
agent,
197+
body,
198+
}) {
199+
// If we can, we should send it as a single buffer so it sets a Content-Length header.
200+
if (body && Array.isArray(body)) {
201+
body = Buffer.from(await collect(body));
202+
} else if (body) {
203+
body = asyncIteratorToStream(body);
204+
}
205+
return new Promise((resolve, reject) => {
206+
get(
207+
{
208+
url,
209+
method,
210+
headers,
211+
agent,
212+
body,
213+
},
214+
(err, res) => {
215+
if (err) return reject(err)
216+
try {
217+
const iter = fromNodeStream(res);
218+
resolve({
219+
url: res.url,
220+
method: res.method,
221+
statusCode: res.statusCode,
222+
statusMessage: res.statusMessage,
223+
body: iter,
224+
headers: res.headers,
225+
});
226+
} catch (e) {
227+
reject(e);
228+
}
229+
}
230+
);
231+
})
232+
}
233+
234+
var index = { request };
235+
236+
exports.default = index;
237+
exports.request = request;

http/node/index.d.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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 HTTP or HTTPS agent that manages connections for the HTTP client (Node.js only)
25+
*/
26+
agent?: any;
27+
/**
28+
* - An async iterator of Uint8Arrays that make up the body of POST requests
29+
*/
30+
body?: any;
31+
/**
32+
* - Reserved for future use (emitting `GitProgressEvent`s)
33+
*/
34+
onProgress?: ProgressCallback;
35+
/**
36+
* - Reserved for future use (canceling a request)
37+
*/
38+
signal?: any;
39+
};
40+
export type GitHttpResponse = {
41+
/**
42+
* - The final URL that was fetched after any redirects
43+
*/
44+
url: string;
45+
/**
46+
* - The HTTP method that was used
47+
*/
48+
method?: string;
49+
/**
50+
* - HTTP response headers
51+
*/
52+
headers?: {
53+
[x: string]: string;
54+
};
55+
/**
56+
* - An async iterator of Uint8Arrays that make up the body of the response
57+
*/
58+
body?: any;
59+
/**
60+
* - The HTTP status code
61+
*/
62+
statusCode: number;
63+
/**
64+
* - The HTTP status message
65+
*/
66+
statusMessage: string;
67+
};
68+
export type HttpFetch = (request: GitHttpRequest) => Promise<GitHttpResponse>;
69+
export type HttpClient = {
70+
request: HttpFetch;
71+
};
72+
declare namespace index {
73+
export { request };
74+
}
75+
/**
76+
* HttpClient
77+
*
78+
* @param {GitHttpRequest} request
79+
* @returns {Promise<GitHttpResponse>}
80+
*/
81+
export function request({ onProgress, url, method, headers, agent, body, }: GitHttpRequest): Promise<GitHttpResponse>;

0 commit comments

Comments
 (0)