workbox-streams.dev.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. this.workbox = this.workbox || {};
  2. this.workbox.streams = (function (exports, logger_js, assert_js, Deferred_js, canConstructReadableStream_js) {
  3. 'use strict';
  4. try {
  5. self['workbox:streams:5.1.4'] && _();
  6. } catch (e) {}
  7. /*
  8. Copyright 2018 Google LLC
  9. Use of this source code is governed by an MIT-style
  10. license that can be found in the LICENSE file or at
  11. https://opensource.org/licenses/MIT.
  12. */
  13. /**
  14. * Takes either a Response, a ReadableStream, or a
  15. * [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the
  16. * ReadableStreamReader object associated with it.
  17. *
  18. * @param {module:workbox-streams.StreamSource} source
  19. * @return {ReadableStreamReader}
  20. * @private
  21. */
  22. function _getReaderFromSource(source) {
  23. if (source instanceof Response) {
  24. return source.body.getReader();
  25. }
  26. if (source instanceof ReadableStream) {
  27. return source.getReader();
  28. }
  29. return new Response(source).body.getReader();
  30. }
  31. /**
  32. * Takes multiple source Promises, each of which could resolve to a Response, a
  33. * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).
  34. *
  35. * Returns an object exposing a ReadableStream with each individual stream's
  36. * data returned in sequence, along with a Promise which signals when the
  37. * stream is finished (useful for passing to a FetchEvent's waitUntil()).
  38. *
  39. * @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises
  40. * @return {Object<{done: Promise, stream: ReadableStream}>}
  41. *
  42. * @memberof module:workbox-streams
  43. */
  44. function concatenate(sourcePromises) {
  45. {
  46. assert_js.assert.isArray(sourcePromises, {
  47. moduleName: 'workbox-streams',
  48. funcName: 'concatenate',
  49. paramName: 'sourcePromises'
  50. });
  51. }
  52. const readerPromises = sourcePromises.map(sourcePromise => {
  53. return Promise.resolve(sourcePromise).then(source => {
  54. return _getReaderFromSource(source);
  55. });
  56. });
  57. const streamDeferred = new Deferred_js.Deferred();
  58. let i = 0;
  59. const logMessages = [];
  60. const stream = new ReadableStream({
  61. pull(controller) {
  62. return readerPromises[i].then(reader => reader.read()).then(result => {
  63. if (result.done) {
  64. {
  65. logMessages.push(['Reached the end of source:', sourcePromises[i]]);
  66. }
  67. i++;
  68. if (i >= readerPromises.length) {
  69. // Log all the messages in the group at once in a single group.
  70. {
  71. logger_js.logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);
  72. for (const message of logMessages) {
  73. if (Array.isArray(message)) {
  74. logger_js.logger.log(...message);
  75. } else {
  76. logger_js.logger.log(message);
  77. }
  78. }
  79. logger_js.logger.log('Finished reading all sources.');
  80. logger_js.logger.groupEnd();
  81. }
  82. controller.close();
  83. streamDeferred.resolve();
  84. return;
  85. } // The `pull` method is defined because we're inside it.
  86. return this.pull(controller);
  87. } else {
  88. controller.enqueue(result.value);
  89. }
  90. }).catch(error => {
  91. {
  92. logger_js.logger.error('An error occurred:', error);
  93. }
  94. streamDeferred.reject(error);
  95. throw error;
  96. });
  97. },
  98. cancel() {
  99. {
  100. logger_js.logger.warn('The ReadableStream was cancelled.');
  101. }
  102. streamDeferred.resolve();
  103. }
  104. });
  105. return {
  106. done: streamDeferred.promise,
  107. stream
  108. };
  109. }
  110. /*
  111. Copyright 2018 Google LLC
  112. Use of this source code is governed by an MIT-style
  113. license that can be found in the LICENSE file or at
  114. https://opensource.org/licenses/MIT.
  115. */
  116. /**
  117. * This is a utility method that determines whether the current browser supports
  118. * the features required to create streamed responses. Currently, it checks if
  119. * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
  120. * is available.
  121. *
  122. * @private
  123. * @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
  124. * `'text/html'` will be used by default.
  125. * @return {boolean} `true`, if the current browser meets the requirements for
  126. * streaming responses, and `false` otherwise.
  127. *
  128. * @memberof module:workbox-streams
  129. */
  130. function createHeaders(headersInit = {}) {
  131. // See https://github.com/GoogleChrome/workbox/issues/1461
  132. const headers = new Headers(headersInit);
  133. if (!headers.has('content-type')) {
  134. headers.set('content-type', 'text/html');
  135. }
  136. return headers;
  137. }
  138. /*
  139. Copyright 2018 Google LLC
  140. Use of this source code is governed by an MIT-style
  141. license that can be found in the LICENSE file or at
  142. https://opensource.org/licenses/MIT.
  143. */
  144. /**
  145. * Takes multiple source Promises, each of which could resolve to a Response, a
  146. * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),
  147. * along with a
  148. * [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).
  149. *
  150. * Returns an object exposing a Response whose body consists of each individual
  151. * stream's data returned in sequence, along with a Promise which signals when
  152. * the stream is finished (useful for passing to a FetchEvent's waitUntil()).
  153. *
  154. * @param {Array<Promise<module:workbox-streams.StreamSource>>} sourcePromises
  155. * @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
  156. * `'text/html'` will be used by default.
  157. * @return {Object<{done: Promise, response: Response}>}
  158. *
  159. * @memberof module:workbox-streams
  160. */
  161. function concatenateToResponse(sourcePromises, headersInit) {
  162. const {
  163. done,
  164. stream
  165. } = concatenate(sourcePromises);
  166. const headers = createHeaders(headersInit);
  167. const response = new Response(stream, {
  168. headers
  169. });
  170. return {
  171. done,
  172. response
  173. };
  174. }
  175. /*
  176. Copyright 2018 Google LLC
  177. Use of this source code is governed by an MIT-style
  178. license that can be found in the LICENSE file or at
  179. https://opensource.org/licenses/MIT.
  180. */
  181. /**
  182. * This is a utility method that determines whether the current browser supports
  183. * the features required to create streamed responses. Currently, it checks if
  184. * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
  185. * can be created.
  186. *
  187. * @return {boolean} `true`, if the current browser meets the requirements for
  188. * streaming responses, and `false` otherwise.
  189. *
  190. * @memberof module:workbox-streams
  191. */
  192. function isSupported() {
  193. return canConstructReadableStream_js.canConstructReadableStream();
  194. }
  195. /*
  196. Copyright 2018 Google LLC
  197. Use of this source code is governed by an MIT-style
  198. license that can be found in the LICENSE file or at
  199. https://opensource.org/licenses/MIT.
  200. */
  201. /**
  202. * A shortcut to create a strategy that could be dropped-in to Workbox's router.
  203. *
  204. * On browsers that do not support constructing new `ReadableStream`s, this
  205. * strategy will automatically wait for all the `sourceFunctions` to complete,
  206. * and create a final response that concatenates their values together.
  207. *
  208. * @param {Array<function({event, request, url, params})>} sourceFunctions
  209. * An array of functions similar to {@link module:workbox-routing~handlerCallback}
  210. * but that instead return a {@link module:workbox-streams.StreamSource} (or a
  211. * Promise which resolves to one).
  212. * @param {HeadersInit} [headersInit] If there's no `Content-Type` specified,
  213. * `'text/html'` will be used by default.
  214. * @return {module:workbox-routing~handlerCallback}
  215. * @memberof module:workbox-streams
  216. */
  217. function strategy(sourceFunctions, headersInit) {
  218. return async ({
  219. event,
  220. request,
  221. url,
  222. params
  223. }) => {
  224. const sourcePromises = sourceFunctions.map(fn => {
  225. // Ensure the return value of the function is always a promise.
  226. return Promise.resolve(fn({
  227. event,
  228. request,
  229. url,
  230. params
  231. }));
  232. });
  233. if (isSupported()) {
  234. const {
  235. done,
  236. response
  237. } = concatenateToResponse(sourcePromises, headersInit);
  238. if (event) {
  239. event.waitUntil(done);
  240. }
  241. return response;
  242. }
  243. {
  244. logger_js.logger.log(`The current browser doesn't support creating response ` + `streams. Falling back to non-streaming response instead.`);
  245. } // Fallback to waiting for everything to finish, and concatenating the
  246. // responses.
  247. const blobPartsPromises = sourcePromises.map(async sourcePromise => {
  248. const source = await sourcePromise;
  249. if (source instanceof Response) {
  250. return source.blob();
  251. } else {
  252. // Technically, a `StreamSource` object can include any valid
  253. // `BodyInit` type, including `FormData` and `URLSearchParams`, which
  254. // cannot be passed to the Blob constructor directly, so we have to
  255. // convert them to actual Blobs first.
  256. return new Response(source).blob();
  257. }
  258. });
  259. const blobParts = await Promise.all(blobPartsPromises);
  260. const headers = createHeaders(headersInit); // Constructing a new Response from a Blob source is well-supported.
  261. // So is constructing a new Blob from multiple source Blobs or strings.
  262. return new Response(new Blob(blobParts), {
  263. headers
  264. });
  265. };
  266. }
  267. exports.concatenate = concatenate;
  268. exports.concatenateToResponse = concatenateToResponse;
  269. exports.isSupported = isSupported;
  270. exports.strategy = strategy;
  271. return exports;
  272. }({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
  273. //# sourceMappingURL=workbox-streams.dev.js.map