@serwist/streams 9.5.7 → 9.5.9

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.
@@ -0,0 +1,77 @@
1
+ import { RouteHandlerCallback, RouteHandlerCallbackOptions } from "serwist";
2
+
3
+ //#region src/_types.d.ts
4
+ type StreamSource = Response | ReadableStream | BodyInit;
5
+ //#endregion
6
+ //#region src/concatenate.d.ts
7
+ /**
8
+ * Takes multiple source Promises, each of which could resolve to a Response, a
9
+ * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).
10
+ *
11
+ * Returns an object exposing a ReadableStream with each individual stream's
12
+ * data returned in sequence, along with a Promise which signals when the
13
+ * stream is finished (useful for passing to a FetchEvent's waitUntil()).
14
+ *
15
+ * @param sourcePromises
16
+ * @returns
17
+ */
18
+ declare function concatenate(sourcePromises: Promise<StreamSource>[]): {
19
+ done: Promise<void>;
20
+ stream: ReadableStream;
21
+ };
22
+ //#endregion
23
+ //#region src/concatenateToResponse.d.ts
24
+ /**
25
+ * Takes multiple source Promises, each of which could resolve to a Response, a
26
+ * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),
27
+ * along with a
28
+ * [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).
29
+ *
30
+ * Returns an object exposing a Response whose body consists of each individual
31
+ * stream's data returned in sequence, along with a Promise which signals when
32
+ * the stream is finished (useful for passing to a FetchEvent's waitUntil()).
33
+ *
34
+ * @param sourcePromises
35
+ * @param headersInit If there's no `Content-Type` specified,`'text/html'` will be used by default.
36
+ * @returns
37
+ */
38
+ declare function concatenateToResponse(sourcePromises: Promise<StreamSource>[], headersInit: HeadersInit): {
39
+ done: Promise<void>;
40
+ response: Response;
41
+ };
42
+ //#endregion
43
+ //#region src/isSupported.d.ts
44
+ /**
45
+ * This is a utility method that determines whether the current browser supports
46
+ * the features required to create streamed responses. Currently, it checks if
47
+ * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
48
+ * can be created.
49
+ *
50
+ * @returns `true`, if the current browser meets the requirements for
51
+ * streaming responses, and `false` otherwise.
52
+ */
53
+ declare const isSupported: () => boolean;
54
+ //#endregion
55
+ //#region src/strategy.d.ts
56
+ type StreamsHandlerCallback = ({
57
+ url,
58
+ request,
59
+ event,
60
+ params
61
+ }: RouteHandlerCallbackOptions) => Promise<StreamSource> | StreamSource;
62
+ /**
63
+ * A shortcut to create a strategy that could be dropped-in to Serwist's `Router`.
64
+ *
65
+ * On browsers that do not support constructing new `ReadableStream`s, this
66
+ * strategy will automatically wait for all the `sourceFunctions` to complete,
67
+ * and create a final response that concatenates their values together.
68
+ *
69
+ * @param sourceFunctions An array of functions similar to `serwist.handlerCallback`
70
+ * but that instead return a `@serwist/streams.StreamSource` (or a Promise which resolves to one).
71
+ * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.
72
+ * @returns
73
+ */
74
+ declare const strategy: (sourceFunctions: StreamsHandlerCallback[], headersInit: HeadersInit) => RouteHandlerCallback;
75
+ //#endregion
76
+ export { StreamSource, type StreamsHandlerCallback, concatenate, concatenateToResponse, isSupported, strategy };
77
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/_types.ts","../src/concatenate.ts","../src/concatenateToResponse.ts","../src/isSupported.ts","../src/strategy.ts"],"mappings":";;;KAQY,YAAA,GAAe,QAAA,GAAW,cAAA,GAAiB,QAAA;;;;;AAAvD;;;;;;;;;iBCsCS,WAAA,CAAY,cAAA,EAAgB,OAAA,CAAQ,YAAA;EAC3C,IAAA,EAAM,OAAA;EACN,MAAA,EAAQ,cAAA;AAAA;;;;;ADxCV;;;;;;;;;;;;iBEkBS,qBAAA,CAAsB,cAAA,EAAgB,OAAA,CAAQ,YAAA,KAAiB,WAAA,EAAa,WAAA;EAAgB,IAAA,EAAM,OAAA;EAAe,QAAA,EAAU,QAAA;AAAA;;;;;;AFlBpI;;;;;;cGWa,WAAA;;;KCHD,sBAAA;EAA4B,GAAA;EAAK,OAAA;EAAS,KAAA;EAAO;AAAA,GAAU,2BAAA,KAAgC,OAAA,CAAQ,YAAA,IAAgB,YAAA;AJR/H;;;;;;;;;;;;AAAA,cIsBa,QAAA,GAAY,eAAA,EAAiB,sBAAA,IAA0B,WAAA,EAAa,WAAA,KAAc,oBAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,181 @@
1
+ import { Deferred, SerwistError, assert, canConstructReadableStream, logger } from "serwist/internal";
2
+ //#region src/concatenate.ts
3
+ /**
4
+ * Takes either a Response, a ReadableStream, or a
5
+ * [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the
6
+ * ReadableStreamReader object associated with it.
7
+ *
8
+ * @param source
9
+ * @returns
10
+ * @private
11
+ */
12
+ function _getReaderFromSource(source) {
13
+ if (source instanceof Response) {
14
+ if (source.body) return source.body.getReader();
15
+ throw new SerwistError("opaque-streams-source", { type: source.type });
16
+ }
17
+ if (source instanceof ReadableStream) return source.getReader();
18
+ return new Response(source).body.getReader();
19
+ }
20
+ /**
21
+ * Takes multiple source Promises, each of which could resolve to a Response, a
22
+ * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).
23
+ *
24
+ * Returns an object exposing a ReadableStream with each individual stream's
25
+ * data returned in sequence, along with a Promise which signals when the
26
+ * stream is finished (useful for passing to a FetchEvent's waitUntil()).
27
+ *
28
+ * @param sourcePromises
29
+ * @returns
30
+ */
31
+ function concatenate(sourcePromises) {
32
+ if (process.env.NODE_ENV !== "production") assert.isArray(sourcePromises, {
33
+ moduleName: "@serwist/streams",
34
+ funcName: "concatenate",
35
+ paramName: "sourcePromises"
36
+ });
37
+ const readerPromises = sourcePromises.map((sourcePromise) => {
38
+ return Promise.resolve(sourcePromise).then((source) => {
39
+ return _getReaderFromSource(source);
40
+ });
41
+ });
42
+ const streamDeferred = new Deferred();
43
+ let i = 0;
44
+ const logMessages = [];
45
+ const stream = new ReadableStream({
46
+ pull(controller) {
47
+ return readerPromises[i].then((reader) => {
48
+ if (reader instanceof ReadableStreamDefaultReader) return reader.read();
49
+ }).then((result) => {
50
+ if (result?.done) {
51
+ if (process.env.NODE_ENV !== "production") logMessages.push(["Reached the end of source:", sourcePromises[i]]);
52
+ i++;
53
+ if (i >= readerPromises.length) {
54
+ if (process.env.NODE_ENV !== "production") {
55
+ logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);
56
+ for (const message of logMessages) if (Array.isArray(message)) logger.log(...message);
57
+ else logger.log(message);
58
+ logger.log("Finished reading all sources.");
59
+ logger.groupEnd();
60
+ }
61
+ controller.close();
62
+ streamDeferred.resolve();
63
+ return;
64
+ }
65
+ return this.pull(controller);
66
+ }
67
+ controller.enqueue(result?.value);
68
+ }).catch((error) => {
69
+ if (process.env.NODE_ENV !== "production") logger.error("An error occurred:", error);
70
+ streamDeferred.reject(error);
71
+ throw error;
72
+ });
73
+ },
74
+ cancel() {
75
+ if (process.env.NODE_ENV !== "production") logger.warn("The ReadableStream was cancelled.");
76
+ streamDeferred.resolve();
77
+ }
78
+ });
79
+ return {
80
+ done: streamDeferred.promise,
81
+ stream
82
+ };
83
+ }
84
+ //#endregion
85
+ //#region src/utils/createHeaders.ts
86
+ /**
87
+ * This is a utility method that determines whether the current browser supports
88
+ * the features required to create streamed responses. Currently, it checks if
89
+ * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
90
+ * is available.
91
+ *
92
+ * @private
93
+ * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.
94
+ * @returns `true`, if the current browser meets the requirements for
95
+ * streaming responses, and `false` otherwise.
96
+ */
97
+ function createHeaders(headersInit = {}) {
98
+ const headers = new Headers(headersInit);
99
+ if (!headers.has("content-type")) headers.set("content-type", "text/html");
100
+ return headers;
101
+ }
102
+ //#endregion
103
+ //#region src/concatenateToResponse.ts
104
+ /**
105
+ * Takes multiple source Promises, each of which could resolve to a Response, a
106
+ * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),
107
+ * along with a
108
+ * [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).
109
+ *
110
+ * Returns an object exposing a Response whose body consists of each individual
111
+ * stream's data returned in sequence, along with a Promise which signals when
112
+ * the stream is finished (useful for passing to a FetchEvent's waitUntil()).
113
+ *
114
+ * @param sourcePromises
115
+ * @param headersInit If there's no `Content-Type` specified,`'text/html'` will be used by default.
116
+ * @returns
117
+ */
118
+ function concatenateToResponse(sourcePromises, headersInit) {
119
+ const { done, stream } = concatenate(sourcePromises);
120
+ const headers = createHeaders(headersInit);
121
+ return {
122
+ done,
123
+ response: new Response(stream, { headers })
124
+ };
125
+ }
126
+ //#endregion
127
+ //#region src/isSupported.ts
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
+ * can be created.
133
+ *
134
+ * @returns `true`, if the current browser meets the requirements for
135
+ * streaming responses, and `false` otherwise.
136
+ */
137
+ const isSupported = () => canConstructReadableStream();
138
+ //#endregion
139
+ //#region src/strategy.ts
140
+ /**
141
+ * A shortcut to create a strategy that could be dropped-in to Serwist's `Router`.
142
+ *
143
+ * On browsers that do not support constructing new `ReadableStream`s, this
144
+ * strategy will automatically wait for all the `sourceFunctions` to complete,
145
+ * and create a final response that concatenates their values together.
146
+ *
147
+ * @param sourceFunctions An array of functions similar to `serwist.handlerCallback`
148
+ * but that instead return a `@serwist/streams.StreamSource` (or a Promise which resolves to one).
149
+ * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.
150
+ * @returns
151
+ */
152
+ const strategy = (sourceFunctions, headersInit) => {
153
+ return async ({ event, request, url, params }) => {
154
+ const sourcePromises = sourceFunctions.map((fn) => {
155
+ return Promise.resolve(fn({
156
+ event,
157
+ request,
158
+ url,
159
+ params
160
+ }));
161
+ });
162
+ if (isSupported()) {
163
+ const { done, response } = concatenateToResponse(sourcePromises, headersInit);
164
+ if (event) event.waitUntil(done);
165
+ return response;
166
+ }
167
+ if (process.env.NODE_ENV !== "production") logger.log("The current browser doesn't support creating response streams. Falling back to non-streaming response instead.");
168
+ const blobPartsPromises = sourcePromises.map(async (sourcePromise) => {
169
+ const source = await sourcePromise;
170
+ if (source instanceof Response) return source.blob();
171
+ return new Response(source).blob();
172
+ });
173
+ const blobParts = await Promise.all(blobPartsPromises);
174
+ const headers = createHeaders(headersInit);
175
+ return new Response(new Blob(blobParts), { headers });
176
+ };
177
+ };
178
+ //#endregion
179
+ export { concatenate, concatenateToResponse, isSupported, strategy };
180
+
181
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/concatenate.ts","../src/utils/createHeaders.ts","../src/concatenateToResponse.ts","../src/isSupported.ts","../src/strategy.ts"],"sourcesContent":["/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\nimport { assert, Deferred, logger, SerwistError } from \"serwist/internal\";\n\nimport type { StreamSource } from \"./_types.js\";\n\n/**\n * Takes either a Response, a ReadableStream, or a\n * [BodyInit](https://fetch.spec.whatwg.org/#bodyinit) and returns the\n * ReadableStreamReader object associated with it.\n *\n * @param source\n * @returns\n * @private\n */\nfunction _getReaderFromSource(source: StreamSource): ReadableStreamReader<unknown> {\n if (source instanceof Response) {\n // See https://github.com/GoogleChrome/workbox/issues/2998\n if (source.body) {\n return source.body.getReader();\n }\n throw new SerwistError(\"opaque-streams-source\", { type: source.type });\n }\n if (source instanceof ReadableStream) {\n return source.getReader();\n }\n return new Response(source as BodyInit).body!.getReader();\n}\n\n/**\n * Takes multiple source Promises, each of which could resolve to a Response, a\n * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).\n *\n * Returns an object exposing a ReadableStream with each individual stream's\n * data returned in sequence, along with a Promise which signals when the\n * stream is finished (useful for passing to a FetchEvent's waitUntil()).\n *\n * @param sourcePromises\n * @returns\n */\nfunction concatenate(sourcePromises: Promise<StreamSource>[]): {\n done: Promise<void>;\n stream: ReadableStream;\n} {\n if (process.env.NODE_ENV !== \"production\") {\n assert!.isArray(sourcePromises, {\n moduleName: \"@serwist/streams\",\n funcName: \"concatenate\",\n paramName: \"sourcePromises\",\n });\n }\n\n const readerPromises = sourcePromises.map((sourcePromise) => {\n return Promise.resolve(sourcePromise).then((source) => {\n return _getReaderFromSource(source);\n });\n });\n\n const streamDeferred: Deferred<void> = new Deferred();\n\n let i = 0;\n const logMessages: any[] = [];\n const stream = new ReadableStream({\n pull(controller: ReadableStreamDefaultController<any>) {\n return readerPromises[i]\n .then((reader) => {\n if (reader instanceof ReadableStreamDefaultReader) {\n return reader.read();\n }\n return;\n })\n .then((result) => {\n if (result?.done) {\n if (process.env.NODE_ENV !== \"production\") {\n logMessages.push([\"Reached the end of source:\", sourcePromises[i]]);\n }\n\n i++;\n if (i >= readerPromises.length) {\n // Log all the messages in the group at once in a single group.\n if (process.env.NODE_ENV !== \"production\") {\n logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);\n for (const message of logMessages) {\n if (Array.isArray(message)) {\n logger.log(...message);\n } else {\n logger.log(message);\n }\n }\n logger.log(\"Finished reading all sources.\");\n logger.groupEnd();\n }\n\n controller.close();\n streamDeferred.resolve();\n return;\n }\n\n // The `pull` method is defined because we're inside it.\n return this.pull!(controller);\n }\n controller.enqueue(result?.value);\n })\n .catch((error) => {\n if (process.env.NODE_ENV !== \"production\") {\n logger.error(\"An error occurred:\", error);\n }\n streamDeferred.reject(error);\n throw error;\n });\n },\n\n cancel() {\n if (process.env.NODE_ENV !== \"production\") {\n logger.warn(\"The ReadableStream was cancelled.\");\n }\n\n streamDeferred.resolve();\n },\n });\n\n return { done: streamDeferred.promise, stream };\n}\n\nexport { concatenate };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\n/**\n * This is a utility method that determines whether the current browser supports\n * the features required to create streamed responses. Currently, it checks if\n * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)\n * is available.\n *\n * @private\n * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.\n * @returns `true`, if the current browser meets the requirements for\n * streaming responses, and `false` otherwise.\n */\nfunction createHeaders(headersInit = {}): Headers {\n // See https://github.com/GoogleChrome/workbox/issues/1461\n const headers = new Headers(headersInit);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html\");\n }\n return headers;\n}\n\nexport { createHeaders };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\nimport type { StreamSource } from \"./_types.js\";\nimport { concatenate } from \"./concatenate.js\";\nimport { createHeaders } from \"./utils/createHeaders.js\";\n\n/**\n * Takes multiple source Promises, each of which could resolve to a Response, a\n * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),\n * along with a\n * [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).\n *\n * Returns an object exposing a Response whose body consists of each individual\n * stream's data returned in sequence, along with a Promise which signals when\n * the stream is finished (useful for passing to a FetchEvent's waitUntil()).\n *\n * @param sourcePromises\n * @param headersInit If there's no `Content-Type` specified,`'text/html'` will be used by default.\n * @returns\n */\nfunction concatenateToResponse(sourcePromises: Promise<StreamSource>[], headersInit: HeadersInit): { done: Promise<void>; response: Response } {\n const { done, stream } = concatenate(sourcePromises);\n\n const headers = createHeaders(headersInit);\n const response = new Response(stream, { headers });\n\n return { done, response };\n}\n\nexport { concatenateToResponse };\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\nimport { canConstructReadableStream } from \"serwist/internal\";\n\n/**\n * This is a utility method that determines whether the current browser supports\n * the features required to create streamed responses. Currently, it checks if\n * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)\n * can be created.\n *\n * @returns `true`, if the current browser meets the requirements for\n * streaming responses, and `false` otherwise.\n */\nexport const isSupported = (): boolean => canConstructReadableStream();\n","/*\n Copyright 2018 Google LLC\n\n Use of this source code is governed by an MIT-style\n license that can be found in the LICENSE file or at\n https://opensource.org/licenses/MIT.\n*/\n\nimport type { RouteHandlerCallback, RouteHandlerCallbackOptions } from \"serwist\";\nimport { logger } from \"serwist/internal\";\n\nimport type { StreamSource } from \"./_types.js\";\nimport { concatenateToResponse } from \"./concatenateToResponse.js\";\nimport { isSupported } from \"./isSupported.js\";\nimport { createHeaders } from \"./utils/createHeaders.js\";\n\nexport type StreamsHandlerCallback = ({ url, request, event, params }: RouteHandlerCallbackOptions) => Promise<StreamSource> | StreamSource;\n\n/**\n * A shortcut to create a strategy that could be dropped-in to Serwist's `Router`.\n *\n * On browsers that do not support constructing new `ReadableStream`s, this\n * strategy will automatically wait for all the `sourceFunctions` to complete,\n * and create a final response that concatenates their values together.\n *\n * @param sourceFunctions An array of functions similar to `serwist.handlerCallback`\n * but that instead return a `@serwist/streams.StreamSource` (or a Promise which resolves to one).\n * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.\n * @returns\n */\nexport const strategy = (sourceFunctions: StreamsHandlerCallback[], headersInit: HeadersInit): RouteHandlerCallback => {\n return async ({ event, request, url, params }: RouteHandlerCallbackOptions) => {\n const sourcePromises = sourceFunctions.map((fn) => {\n // Ensure the return value of the function is always a promise.\n return Promise.resolve(fn({ event, request, url, params }));\n });\n\n if (isSupported()) {\n const { done, response } = concatenateToResponse(sourcePromises, headersInit);\n\n if (event) {\n event.waitUntil(done);\n }\n return response;\n }\n\n if (process.env.NODE_ENV !== \"production\") {\n logger.log(`The current browser doesn't support creating response ` + \"streams. Falling back to non-streaming response instead.\");\n }\n\n // Fallback to waiting for everything to finish, and concatenating the\n // responses.\n const blobPartsPromises = sourcePromises.map(async (sourcePromise) => {\n const source = await sourcePromise;\n if (source instanceof Response) {\n return source.blob();\n }\n // Technically, a `StreamSource` object can include any valid\n // `BodyInit` type, including `FormData` and `URLSearchParams`, which\n // cannot be passed to the Blob constructor directly, so we have to\n // convert them to actual Blobs first.\n return new Response(source).blob();\n });\n const blobParts = await Promise.all(blobPartsPromises);\n const headers = createHeaders(headersInit);\n\n // Constructing a new Response from a Blob source is well-supported.\n // So is constructing a new Blob from multiple source Blobs or strings.\n return new Response(new Blob(blobParts), { headers });\n };\n};\n"],"mappings":";;;;;;;;;;;AAqBA,SAAS,qBAAqB,QAAqD;AACjF,KAAI,kBAAkB,UAAU;AAE9B,MAAI,OAAO,KACT,QAAO,OAAO,KAAK,WAAW;AAEhC,QAAM,IAAI,aAAa,yBAAyB,EAAE,MAAM,OAAO,MAAM,CAAC;;AAExE,KAAI,kBAAkB,eACpB,QAAO,OAAO,WAAW;AAE3B,QAAO,IAAI,SAAS,OAAmB,CAAC,KAAM,WAAW;;;;;;;;;;;;;AAc3D,SAAS,YAAY,gBAGnB;AACA,KAAI,QAAQ,IAAI,aAAa,aAC3B,QAAQ,QAAQ,gBAAgB;EAC9B,YAAY;EACZ,UAAU;EACV,WAAW;EACZ,CAAC;CAGJ,MAAM,iBAAiB,eAAe,KAAK,kBAAkB;AAC3D,SAAO,QAAQ,QAAQ,cAAc,CAAC,MAAM,WAAW;AACrD,UAAO,qBAAqB,OAAO;IACnC;GACF;CAEF,MAAM,iBAAiC,IAAI,UAAU;CAErD,IAAI,IAAI;CACR,MAAM,cAAqB,EAAE;CAC7B,MAAM,SAAS,IAAI,eAAe;EAChC,KAAK,YAAkD;AACrD,UAAO,eAAe,GACnB,MAAM,WAAW;AAChB,QAAI,kBAAkB,4BACpB,QAAO,OAAO,MAAM;KAGtB,CACD,MAAM,WAAW;AAChB,QAAI,QAAQ,MAAM;AAChB,SAAI,QAAQ,IAAI,aAAa,aAC3B,aAAY,KAAK,CAAC,8BAA8B,eAAe,GAAG,CAAC;AAGrE;AACA,SAAI,KAAK,eAAe,QAAQ;AAE9B,UAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,cAAO,eAAe,iBAAiB,eAAe,OAAO,WAAW;AACxE,YAAK,MAAM,WAAW,YACpB,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,IAAI,GAAG,QAAQ;WAEtB,QAAO,IAAI,QAAQ;AAGvB,cAAO,IAAI,gCAAgC;AAC3C,cAAO,UAAU;;AAGnB,iBAAW,OAAO;AAClB,qBAAe,SAAS;AACxB;;AAIF,YAAO,KAAK,KAAM,WAAW;;AAE/B,eAAW,QAAQ,QAAQ,MAAM;KACjC,CACD,OAAO,UAAU;AAChB,QAAI,QAAQ,IAAI,aAAa,aAC3B,QAAO,MAAM,sBAAsB,MAAM;AAE3C,mBAAe,OAAO,MAAM;AAC5B,UAAM;KACN;;EAGN,SAAS;AACP,OAAI,QAAQ,IAAI,aAAa,aAC3B,QAAO,KAAK,oCAAoC;AAGlD,kBAAe,SAAS;;EAE3B,CAAC;AAEF,QAAO;EAAE,MAAM,eAAe;EAAS;EAAQ;;;;;;;;;;;;;;;AC5GjD,SAAS,cAAc,cAAc,EAAE,EAAW;CAEhD,MAAM,UAAU,IAAI,QAAQ,YAAY;AACxC,KAAI,CAAC,QAAQ,IAAI,eAAe,CAC9B,SAAQ,IAAI,gBAAgB,YAAY;AAE1C,QAAO;;;;;;;;;;;;;;;;;;ACCT,SAAS,sBAAsB,gBAAyC,aAAuE;CAC7I,MAAM,EAAE,MAAM,WAAW,YAAY,eAAe;CAEpD,MAAM,UAAU,cAAc,YAAY;AAG1C,QAAO;EAAE;EAAM,UAAA,IAFM,SAAS,QAAQ,EAAE,SAAS,CAE1B;EAAE;;;;;;;;;;;;;ACb3B,MAAa,oBAA6B,4BAA4B;;;;;;;;;;;;;;;ACWtE,MAAa,YAAY,iBAA2C,gBAAmD;AACrH,QAAO,OAAO,EAAE,OAAO,SAAS,KAAK,aAA0C;EAC7E,MAAM,iBAAiB,gBAAgB,KAAK,OAAO;AAEjD,UAAO,QAAQ,QAAQ,GAAG;IAAE;IAAO;IAAS;IAAK;IAAQ,CAAC,CAAC;IAC3D;AAEF,MAAI,aAAa,EAAE;GACjB,MAAM,EAAE,MAAM,aAAa,sBAAsB,gBAAgB,YAAY;AAE7E,OAAI,MACF,OAAM,UAAU,KAAK;AAEvB,UAAO;;AAGT,MAAI,QAAQ,IAAI,aAAa,aAC3B,QAAO,IAAI,iHAAsH;EAKnI,MAAM,oBAAoB,eAAe,IAAI,OAAO,kBAAkB;GACpE,MAAM,SAAS,MAAM;AACrB,OAAI,kBAAkB,SACpB,QAAO,OAAO,MAAM;AAMtB,UAAO,IAAI,SAAS,OAAO,CAAC,MAAM;IAClC;EACF,MAAM,YAAY,MAAM,QAAQ,IAAI,kBAAkB;EACtD,MAAM,UAAU,cAAc,YAAY;AAI1C,SAAO,IAAI,SAAS,IAAI,KAAK,UAAU,EAAE,EAAE,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serwist/streams",
3
- "version": "9.5.7",
3
+ "version": "9.5.9",
4
4
  "type": "module",
5
5
  "description": "A library that makes it easier to work with Streams in the browser.",
6
6
  "files": [
@@ -23,22 +23,21 @@
23
23
  "repository": "https://github.com/serwist/serwist",
24
24
  "bugs": "https://github.com/serwist/serwist/issues",
25
25
  "homepage": "https://serwist.pages.dev",
26
- "main": "./dist/index.js",
27
- "types": "./dist/index.d.ts",
26
+ "main": "./dist/index.mjs",
27
+ "types": "./dist/index.d.mts",
28
28
  "exports": {
29
29
  ".": {
30
- "types": "./dist/index.d.ts",
31
- "default": "./dist/index.js"
30
+ "types": "./dist/index.d.mts",
31
+ "default": "./dist/index.mjs"
32
32
  },
33
33
  "./package.json": "./package.json"
34
34
  },
35
35
  "dependencies": {
36
- "serwist": "9.5.7"
36
+ "serwist": "9.5.9"
37
37
  },
38
38
  "devDependencies": {
39
- "rollup": "4.59.0",
40
- "typescript": "5.9.3",
41
- "@serwist/configs": "9.5.7"
39
+ "tsdown": "0.21.10",
40
+ "typescript": "6.0.3"
42
41
  },
43
42
  "peerDependencies": {
44
43
  "typescript": ">=5.0.0"
@@ -49,8 +48,8 @@
49
48
  }
50
49
  },
51
50
  "scripts": {
52
- "build": "rimraf dist && NODE_ENV=production rollup --config rollup.config.js",
53
- "dev": "rollup --config rollup.config.js --watch",
51
+ "build": "rimraf dist && NODE_ENV=production tsdown",
52
+ "dev": "tsdown --watch",
54
53
  "lint": "biome lint ./src",
55
54
  "typecheck": "tsc"
56
55
  }
package/dist/_types.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export type StreamSource = Response | ReadableStream | BodyInit;
2
- //# sourceMappingURL=_types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_types.d.ts","sourceRoot":"","sources":["../src/_types.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,QAAQ,CAAC"}
@@ -1,18 +0,0 @@
1
- import type { StreamSource } from "./_types.js";
2
- /**
3
- * Takes multiple source Promises, each of which could resolve to a Response, a
4
- * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit).
5
- *
6
- * Returns an object exposing a ReadableStream with each individual stream's
7
- * data returned in sequence, along with a Promise which signals when the
8
- * stream is finished (useful for passing to a FetchEvent's waitUntil()).
9
- *
10
- * @param sourcePromises
11
- * @returns
12
- */
13
- declare function concatenate(sourcePromises: Promise<StreamSource>[]): {
14
- done: Promise<void>;
15
- stream: ReadableStream;
16
- };
17
- export { concatenate };
18
- //# sourceMappingURL=concatenate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"concatenate.d.ts","sourceRoot":"","sources":["../src/concatenate.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAyBhD;;;;;;;;;;GAUG;AACH,iBAAS,WAAW,CAAC,cAAc,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG;IAC7D,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;CACxB,CA+EA;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -1,21 +0,0 @@
1
- import type { StreamSource } from "./_types.js";
2
- /**
3
- * Takes multiple source Promises, each of which could resolve to a Response, a
4
- * ReadableStream, or a [BodyInit](https://fetch.spec.whatwg.org/#bodyinit),
5
- * along with a
6
- * [HeadersInit](https://fetch.spec.whatwg.org/#typedefdef-headersinit).
7
- *
8
- * Returns an object exposing a Response whose body consists of each individual
9
- * stream's data returned in sequence, along with a Promise which signals when
10
- * the stream is finished (useful for passing to a FetchEvent's waitUntil()).
11
- *
12
- * @param sourcePromises
13
- * @param headersInit If there's no `Content-Type` specified,`'text/html'` will be used by default.
14
- * @returns
15
- */
16
- declare function concatenateToResponse(sourcePromises: Promise<StreamSource>[], headersInit: HeadersInit): {
17
- done: Promise<void>;
18
- response: Response;
19
- };
20
- export { concatenateToResponse };
21
- //# sourceMappingURL=concatenateToResponse.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"concatenateToResponse.d.ts","sourceRoot":"","sources":["../src/concatenateToResponse.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD;;;;;;;;;;;;;GAaG;AACH,iBAAS,qBAAqB,CAAC,cAAc,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,WAAW,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAO7I;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
package/dist/index.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import { concatenate } from "./concatenate.js";
2
- import { concatenateToResponse } from "./concatenateToResponse.js";
3
- import { isSupported } from "./isSupported.js";
4
- import type { StreamsHandlerCallback } from "./strategy.js";
5
- import { strategy } from "./strategy.js";
6
- export { concatenate, concatenateToResponse, isSupported, strategy };
7
- export type { StreamsHandlerCallback };
8
- export * from "./_types.js";
9
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AAErE,YAAY,EAAE,sBAAsB,EAAE,CAAC;AAEvC,cAAc,aAAa,CAAC"}
package/dist/index.js DELETED
@@ -1,147 +0,0 @@
1
- import { assert, Deferred, logger, SerwistError, canConstructReadableStream } from 'serwist/internal';
2
-
3
- function _getReaderFromSource(source) {
4
- if (source instanceof Response) {
5
- if (source.body) {
6
- return source.body.getReader();
7
- }
8
- throw new SerwistError("opaque-streams-source", {
9
- type: source.type
10
- });
11
- }
12
- if (source instanceof ReadableStream) {
13
- return source.getReader();
14
- }
15
- return new Response(source).body.getReader();
16
- }
17
- function concatenate(sourcePromises) {
18
- if (process.env.NODE_ENV !== "production") {
19
- assert.isArray(sourcePromises, {
20
- moduleName: "@serwist/streams",
21
- funcName: "concatenate",
22
- paramName: "sourcePromises"
23
- });
24
- }
25
- const readerPromises = sourcePromises.map((sourcePromise)=>{
26
- return Promise.resolve(sourcePromise).then((source)=>{
27
- return _getReaderFromSource(source);
28
- });
29
- });
30
- const streamDeferred = new Deferred();
31
- let i = 0;
32
- const logMessages = [];
33
- const stream = new ReadableStream({
34
- pull (controller) {
35
- return readerPromises[i].then((reader)=>{
36
- if (reader instanceof ReadableStreamDefaultReader) {
37
- return reader.read();
38
- }
39
- return;
40
- }).then((result)=>{
41
- if (result?.done) {
42
- if (process.env.NODE_ENV !== "production") {
43
- logMessages.push([
44
- "Reached the end of source:",
45
- sourcePromises[i]
46
- ]);
47
- }
48
- i++;
49
- if (i >= readerPromises.length) {
50
- if (process.env.NODE_ENV !== "production") {
51
- logger.groupCollapsed(`Concatenating ${readerPromises.length} sources.`);
52
- for (const message of logMessages){
53
- if (Array.isArray(message)) {
54
- logger.log(...message);
55
- } else {
56
- logger.log(message);
57
- }
58
- }
59
- logger.log("Finished reading all sources.");
60
- logger.groupEnd();
61
- }
62
- controller.close();
63
- streamDeferred.resolve();
64
- return;
65
- }
66
- return this.pull(controller);
67
- }
68
- controller.enqueue(result?.value);
69
- }).catch((error)=>{
70
- if (process.env.NODE_ENV !== "production") {
71
- logger.error("An error occurred:", error);
72
- }
73
- streamDeferred.reject(error);
74
- throw error;
75
- });
76
- },
77
- cancel () {
78
- if (process.env.NODE_ENV !== "production") {
79
- logger.warn("The ReadableStream was cancelled.");
80
- }
81
- streamDeferred.resolve();
82
- }
83
- });
84
- return {
85
- done: streamDeferred.promise,
86
- stream
87
- };
88
- }
89
-
90
- function createHeaders(headersInit = {}) {
91
- const headers = new Headers(headersInit);
92
- if (!headers.has("content-type")) {
93
- headers.set("content-type", "text/html");
94
- }
95
- return headers;
96
- }
97
-
98
- function concatenateToResponse(sourcePromises, headersInit) {
99
- const { done, stream } = concatenate(sourcePromises);
100
- const headers = createHeaders(headersInit);
101
- const response = new Response(stream, {
102
- headers
103
- });
104
- return {
105
- done,
106
- response
107
- };
108
- }
109
-
110
- const isSupported = ()=>canConstructReadableStream();
111
-
112
- const strategy = (sourceFunctions, headersInit)=>{
113
- return async ({ event, request, url, params })=>{
114
- const sourcePromises = sourceFunctions.map((fn)=>{
115
- return Promise.resolve(fn({
116
- event,
117
- request,
118
- url,
119
- params
120
- }));
121
- });
122
- if (isSupported()) {
123
- const { done, response } = concatenateToResponse(sourcePromises, headersInit);
124
- if (event) {
125
- event.waitUntil(done);
126
- }
127
- return response;
128
- }
129
- if (process.env.NODE_ENV !== "production") {
130
- logger.log(`The current browser doesn't support creating response ` + "streams. Falling back to non-streaming response instead.");
131
- }
132
- const blobPartsPromises = sourcePromises.map(async (sourcePromise)=>{
133
- const source = await sourcePromise;
134
- if (source instanceof Response) {
135
- return source.blob();
136
- }
137
- return new Response(source).blob();
138
- });
139
- const blobParts = await Promise.all(blobPartsPromises);
140
- const headers = createHeaders(headersInit);
141
- return new Response(new Blob(blobParts), {
142
- headers
143
- });
144
- };
145
- };
146
-
147
- export { concatenate, concatenateToResponse, isSupported, strategy };
@@ -1,11 +0,0 @@
1
- /**
2
- * This is a utility method that determines whether the current browser supports
3
- * the features required to create streamed responses. Currently, it checks if
4
- * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
5
- * can be created.
6
- *
7
- * @returns `true`, if the current browser meets the requirements for
8
- * streaming responses, and `false` otherwise.
9
- */
10
- export declare const isSupported: () => boolean;
11
- //# sourceMappingURL=isSupported.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isSupported.d.ts","sourceRoot":"","sources":["../src/isSupported.ts"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,QAAO,OAAuC,CAAC"}
@@ -1,17 +0,0 @@
1
- import type { RouteHandlerCallback, RouteHandlerCallbackOptions } from "serwist";
2
- import type { StreamSource } from "./_types.js";
3
- export type StreamsHandlerCallback = ({ url, request, event, params }: RouteHandlerCallbackOptions) => Promise<StreamSource> | StreamSource;
4
- /**
5
- * A shortcut to create a strategy that could be dropped-in to Serwist's `Router`.
6
- *
7
- * On browsers that do not support constructing new `ReadableStream`s, this
8
- * strategy will automatically wait for all the `sourceFunctions` to complete,
9
- * and create a final response that concatenates their values together.
10
- *
11
- * @param sourceFunctions An array of functions similar to `serwist.handlerCallback`
12
- * but that instead return a `@serwist/streams.StreamSource` (or a Promise which resolves to one).
13
- * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.
14
- * @returns
15
- */
16
- export declare const strategy: (sourceFunctions: StreamsHandlerCallback[], headersInit: HeadersInit) => RouteHandlerCallback;
17
- //# sourceMappingURL=strategy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,MAAM,MAAM,sBAAsB,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,2BAA2B,KAAK,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;AAE5I;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAI,iBAAiB,sBAAsB,EAAE,EAAE,aAAa,WAAW,KAAG,oBAwC9F,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * This is a utility method that determines whether the current browser supports
3
- * the features required to create streamed responses. Currently, it checks if
4
- * [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/ReadableStream)
5
- * is available.
6
- *
7
- * @private
8
- * @param headersInit If there's no `Content-Type` specified, `'text/html'` will be used by default.
9
- * @returns `true`, if the current browser meets the requirements for
10
- * streaming responses, and `false` otherwise.
11
- */
12
- declare function createHeaders(headersInit?: {}): Headers;
13
- export { createHeaders };
14
- //# sourceMappingURL=createHeaders.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createHeaders.d.ts","sourceRoot":"","sources":["../../src/utils/createHeaders.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,iBAAS,aAAa,CAAC,WAAW,KAAK,GAAG,OAAO,CAOhD;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}