workbox-streams.dev.js 11 KB

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