webhoster 0.3.1 → 0.3.2

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.
@@ -5,7 +5,7 @@
5
5
 
6
6
  /** @typedef {import('stream').Writable} Writable */
7
7
 
8
- import { PassThrough, Readable, pipeline } from 'node:stream';
8
+ import { PassThrough, pipeline } from 'node:stream';
9
9
 
10
10
  import { isWritable } from '../utils/stream.js';
11
11
 
@@ -124,7 +124,7 @@ export default class HttpResponse {
124
124
  async sendRaw(body) {
125
125
  this.body = body;
126
126
  await new Promise((resolve, reject) => {
127
- this.stream.end(body, (err) => (err ? reject(err) : resolve()));
127
+ this.stream.end(body, (error) => (error ? reject(error) : resolve()));
128
128
  });
129
129
  return 0;
130
130
  }
@@ -162,8 +162,8 @@ export default class HttpResponse {
162
162
  // Called directly by user and needs finalizer calls
163
163
 
164
164
  this.isStreaming = true;
165
- for (let i = 0; i < this.finalizers.length; i++) {
166
- const process = this.finalizers[i];
165
+ for (let index = 0; index < this.finalizers.length; index++) {
166
+ const process = this.finalizers[index];
167
167
  const result = process(this);
168
168
  if (result === false) {
169
169
  break;
@@ -185,11 +185,11 @@ export default class HttpResponse {
185
185
 
186
186
  this.#pipeline = array[0];
187
187
  // @ts-ignore Bad typings
188
- pipeline(array, (err) => {
188
+ pipeline(array, (error) => {
189
189
  this.#pipelineComplete = true;
190
190
  let nextCallback;
191
191
  while ((nextCallback = this.#pipelineCallbacks.shift()) != null) {
192
- nextCallback(err);
192
+ nextCallback(error);
193
193
  }
194
194
  });
195
195
  return this.#pipeline;
@@ -209,7 +209,8 @@ export default class HttpResponse {
209
209
  if (body !== undefined) {
210
210
  this.body = body;
211
211
  }
212
- if (this.body instanceof Readable) {
212
+ if (typeof this.body === 'object' && this.body !== null
213
+ && (Symbol.asyncIterator in this.body)) {
213
214
  this.isStreaming = true;
214
215
  this.pipes.push(this.body);
215
216
  }
@@ -234,8 +235,8 @@ export default class HttpResponse {
234
235
  if (!isWritable(this.stream)) return 0;
235
236
  if (this.isStreaming) {
236
237
  await new Promise((resolve, reject) => {
237
- this.getPipeline((err) => {
238
- if (err) reject(err);
238
+ this.getPipeline((error) => {
239
+ if (error) reject(error);
239
240
  resolve();
240
241
  });
241
242
  });
@@ -268,7 +269,8 @@ export default class HttpResponse {
268
269
  this.body = body;
269
270
  }
270
271
 
271
- if (this.body instanceof Readable) {
272
+ if (typeof this.body === 'object' && this.body !== null
273
+ && (Symbol.asyncIterator in this.body)) {
272
274
  this.isStreaming = true;
273
275
  this.pipes.push(this.body);
274
276
  }
@@ -279,9 +281,9 @@ export default class HttpResponse {
279
281
  let needsAsync = false;
280
282
  /** @type {void|Promise<boolean|void>} */
281
283
  let pendingPromise;
282
- let i;
283
- for (i = 0; i < this.finalizers.length; i++) {
284
- const process = this.finalizers[i];
284
+ let index;
285
+ for (index = 0; index < this.finalizers.length; index++) {
286
+ const process = this.finalizers[index];
285
287
  if (needsAsync) {
286
288
  pendingProcessors.push(process);
287
289
  continue;
@@ -301,8 +303,8 @@ export default class HttpResponse {
301
303
  if (pendingPromise) {
302
304
  pendingPromise.then(async (initialResult) => {
303
305
  if (initialResult !== false) {
304
- for (i = 0; i < pendingProcessors.length; i++) {
305
- const process = pendingProcessors[i];
306
+ for (index = 0; index < pendingProcessors.length; index++) {
307
+ const process = pendingProcessors[index];
306
308
  const result = process(this);
307
309
  if (result === true || result == null) {
308
310
  continue;
package/package.json CHANGED
@@ -50,5 +50,5 @@
50
50
  "posttestall": "c8 report"
51
51
  },
52
52
  "type": "module",
53
- "version": "0.3.1"
53
+ "version": "0.3.2"
54
54
  }
@@ -0,0 +1,37 @@
1
+ import test from 'ava';
2
+ import { PassThrough } from 'node:stream';
3
+
4
+ import HttpHandler from '../../../lib/HttpHandler.js';
5
+ import HttpResponse from '../../../lib/HttpResponse.js';
6
+ import HttpTransaction from '../../../lib/HttpTransaction.js';
7
+
8
+ test('middleware can return async iterable body', async (t) => {
9
+ const stream = new PassThrough();
10
+ const reader = new PassThrough();
11
+ stream.pipe(reader);
12
+
13
+ const response = new HttpResponse({ stream, onSendHeaders: () => {} });
14
+ const transaction = new HttpTransaction({ request: {}, response, socket: {}, httpVersion: '1.1' });
15
+
16
+ const handler = new HttpHandler();
17
+
18
+ // Middleware returns an async generator (async iterable)
19
+ const mw = async () => {
20
+ async function* gen() {
21
+ yield Buffer.from('m1-');
22
+ await new Promise((r) => setTimeout(r, 0));
23
+ yield Buffer.from('m2');
24
+ }
25
+ return gen();
26
+ };
27
+
28
+ const result = await handler.processMiddleware(transaction, mw);
29
+ t.truthy(result !== undefined);
30
+
31
+ let out = '';
32
+ for await (const chunk of reader) {
33
+ out += chunk.toString();
34
+ }
35
+
36
+ t.is(out, 'm1-m2');
37
+ });
@@ -0,0 +1,31 @@
1
+ import test from 'ava';
2
+ import { PassThrough } from 'node:stream';
3
+
4
+ import HttpHandler from '../../../lib/HttpHandler.js';
5
+ import HttpResponse from '../../../lib/HttpResponse.js';
6
+
7
+ test('HttpResponse.send() accepts async iterable body', async (t) => {
8
+ const stream = new PassThrough();
9
+ const reader = new PassThrough();
10
+ stream.pipe(reader);
11
+
12
+ const response = new HttpResponse({ stream, onSendHeaders: () => {} });
13
+
14
+ async function* gen() {
15
+ yield Buffer.from('chunk1-');
16
+ // allow microtask scheduling
17
+ await new Promise((r) => setTimeout(r, 0));
18
+ yield Buffer.from('chunk2');
19
+ }
20
+
21
+ response.body = gen();
22
+
23
+ const result = await response.send();
24
+ t.is(result, HttpHandler.END);
25
+
26
+ let out = '';
27
+ for await (const chunk of reader) {
28
+ out += chunk.toString();
29
+ }
30
+ t.is(out, 'chunk1-chunk2');
31
+ });