http-web-index.umd.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = global || self, factory(global.GitHttp = {}));
  5. }(this, (function (exports) { 'use strict';
  6. /**
  7. * @typedef {Object} GitProgressEvent
  8. * @property {string} phase
  9. * @property {number} loaded
  10. * @property {number} total
  11. */
  12. /**
  13. * @callback ProgressCallback
  14. * @param {GitProgressEvent} progress
  15. * @returns {void | Promise<void>}
  16. */
  17. /**
  18. * @typedef {Object} GitHttpRequest
  19. * @property {string} url - The URL to request
  20. * @property {string} [method='GET'] - The HTTP method to use
  21. * @property {Object<string, string>} [headers={}] - Headers to include in the HTTP request
  22. * @property {AsyncIterableIterator<Uint8Array>} [body] - An async iterator of Uint8Arrays that make up the body of POST requests
  23. * @property {ProgressCallback} [onProgress] - Reserved for future use (emitting `GitProgressEvent`s)
  24. * @property {object} [signal] - Reserved for future use (canceling a request)
  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. * @callback HttpFetch
  37. * @param {GitHttpRequest} request
  38. * @returns {Promise<GitHttpResponse>}
  39. */
  40. /**
  41. * @typedef {Object} HttpClient
  42. * @property {HttpFetch} request
  43. */
  44. // Convert a value to an Async Iterator
  45. // This will be easier with async generator functions.
  46. function fromValue(value) {
  47. let queue = [value];
  48. return {
  49. next() {
  50. return Promise.resolve({ done: queue.length === 0, value: queue.pop() })
  51. },
  52. return() {
  53. queue = [];
  54. return {}
  55. },
  56. [Symbol.asyncIterator]() {
  57. return this
  58. },
  59. }
  60. }
  61. function getIterator(iterable) {
  62. if (iterable[Symbol.asyncIterator]) {
  63. return iterable[Symbol.asyncIterator]()
  64. }
  65. if (iterable[Symbol.iterator]) {
  66. return iterable[Symbol.iterator]()
  67. }
  68. if (iterable.next) {
  69. return iterable
  70. }
  71. return fromValue(iterable)
  72. }
  73. // Currently 'for await' upsets my linters.
  74. async function forAwait(iterable, cb) {
  75. const iter = getIterator(iterable);
  76. while (true) {
  77. const { value, done } = await iter.next();
  78. if (value) await cb(value);
  79. if (done) break
  80. }
  81. if (iter.return) iter.return();
  82. }
  83. async function collect(iterable) {
  84. let size = 0;
  85. const buffers = [];
  86. // This will be easier once `for await ... of` loops are available.
  87. await forAwait(iterable, value => {
  88. buffers.push(value);
  89. size += value.byteLength;
  90. });
  91. const result = new Uint8Array(size);
  92. let nextIndex = 0;
  93. for (const buffer of buffers) {
  94. result.set(buffer, nextIndex);
  95. nextIndex += buffer.byteLength;
  96. }
  97. return result
  98. }
  99. // Convert a web ReadableStream (not Node stream!) to an Async Iterator
  100. // adapted from https://jakearchibald.com/2017/async-iterators-and-generators/
  101. function fromStream(stream) {
  102. // Use native async iteration if it's available.
  103. if (stream[Symbol.asyncIterator]) return stream
  104. const reader = stream.getReader();
  105. return {
  106. next() {
  107. return reader.read()
  108. },
  109. return() {
  110. reader.releaseLock();
  111. return {}
  112. },
  113. [Symbol.asyncIterator]() {
  114. return this
  115. },
  116. }
  117. }
  118. /* eslint-env browser */
  119. /**
  120. * HttpClient
  121. *
  122. * @param {GitHttpRequest} request
  123. * @returns {Promise<GitHttpResponse>}
  124. */
  125. async function request({
  126. onProgress,
  127. url,
  128. method = 'GET',
  129. headers = {},
  130. body,
  131. }) {
  132. // streaming uploads aren't possible yet in the browser
  133. if (body) {
  134. body = await collect(body);
  135. }
  136. const res = await fetch(url, { method, headers, body });
  137. const iter =
  138. res.body && res.body.getReader
  139. ? fromStream(res.body)
  140. : [new Uint8Array(await res.arrayBuffer())];
  141. // convert Header object to ordinary JSON
  142. headers = {};
  143. for (const [key, value] of res.headers.entries()) {
  144. headers[key] = value;
  145. }
  146. return {
  147. url: res.url,
  148. method: res.method,
  149. statusCode: res.status,
  150. statusMessage: res.statusText,
  151. body: iter,
  152. headers: headers,
  153. }
  154. }
  155. var index = { request };
  156. exports.default = index;
  157. exports.request = request;
  158. Object.defineProperty(exports, '__esModule', { value: true });
  159. })));