@hono/node-server 1.17.0 → 1.18.0

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.
@@ -1,7 +1,7 @@
1
1
  // src/serve-static.ts
2
2
  import { getMimeType } from "hono/utils/mime";
3
3
  import { createReadStream, lstatSync } from "fs";
4
- import { join, resolve } from "path";
4
+ import { join } from "path";
5
5
  var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
6
6
  var ENCODINGS = {
7
7
  br: ".br",
@@ -34,37 +34,34 @@ var getStats = (path) => {
34
34
  return stats;
35
35
  };
36
36
  var serveStatic = (options = { root: "" }) => {
37
- const root = resolve(options.root || ".");
37
+ const root = options.root || "";
38
38
  const optionPath = options.path;
39
39
  return async (c, next) => {
40
40
  if (c.finalized) {
41
41
  return next();
42
42
  }
43
43
  let filename;
44
- try {
45
- const rawPath = optionPath ?? c.req.path;
46
- if (!optionPath) {
47
- const decodedPath = decodeURIComponent(rawPath);
48
- if (decodedPath.includes("..")) {
49
- await options.onNotFound?.(rawPath, c);
50
- return next();
44
+ if (optionPath) {
45
+ filename = optionPath;
46
+ } else {
47
+ try {
48
+ filename = decodeURIComponent(c.req.path);
49
+ if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
50
+ throw new Error();
51
51
  }
52
+ } catch {
53
+ await options.onNotFound?.(c.req.path, c);
54
+ return next();
52
55
  }
53
- filename = optionPath ?? decodeURIComponent(c.req.path);
54
- } catch {
55
- await options.onNotFound?.(c.req.path, c);
56
- return next();
57
56
  }
58
- const requestPath = options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename;
59
- let path = optionPath ? options.root ? resolve(join(root, optionPath)) : optionPath : resolve(join(root, requestPath));
57
+ let path = join(
58
+ root,
59
+ !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
60
+ );
60
61
  let stats = getStats(path);
61
62
  if (stats && stats.isDirectory()) {
62
63
  const indexFile = options.index ?? "index.html";
63
- path = resolve(join(path, indexFile));
64
- if (!optionPath && !path.startsWith(root)) {
65
- await options.onNotFound?.(path, c);
66
- return next();
67
- }
64
+ path = join(path, indexFile);
68
65
  stats = getStats(path);
69
66
  }
70
67
  if (!stats) {
package/dist/server.js CHANGED
@@ -287,30 +287,24 @@ Object.setPrototypeOf(Response2, GlobalResponse);
287
287
  Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
288
288
 
289
289
  // src/utils.ts
290
- function writeFromReadableStream(stream, writable) {
291
- if (stream.locked) {
292
- throw new TypeError("ReadableStream is locked.");
293
- } else if (writable.destroyed) {
294
- stream.cancel();
295
- return;
296
- }
297
- const reader = stream.getReader();
298
- writable.on("close", cancel);
299
- writable.on("error", cancel);
300
- reader.read().then(flow, cancel);
290
+ async function readWithoutBlocking(readPromise) {
291
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
292
+ }
293
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
294
+ const handleError = () => {
295
+ };
296
+ writable.on("error", handleError);
297
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
301
298
  return reader.closed.finally(() => {
302
- writable.off("close", cancel);
303
- writable.off("error", cancel);
299
+ writable.off("error", handleError);
304
300
  });
305
- function cancel(error) {
306
- reader.cancel(error).catch(() => {
307
- });
301
+ function handleStreamError(error) {
308
302
  if (error) {
309
303
  writable.destroy(error);
310
304
  }
311
305
  }
312
306
  function onDrain() {
313
- reader.read().then(flow, cancel);
307
+ reader.read().then(flow, handleStreamError);
314
308
  }
315
309
  function flow({ done, value }) {
316
310
  try {
@@ -319,13 +313,21 @@ function writeFromReadableStream(stream, writable) {
319
313
  } else if (!writable.write(value)) {
320
314
  writable.once("drain", onDrain);
321
315
  } else {
322
- return reader.read().then(flow, cancel);
316
+ return reader.read().then(flow, handleStreamError);
323
317
  }
324
318
  } catch (e) {
325
- cancel(e);
319
+ handleStreamError(e);
326
320
  }
327
321
  }
328
322
  }
323
+ function writeFromReadableStream(stream, writable) {
324
+ if (stream.locked) {
325
+ throw new TypeError("ReadableStream is locked.");
326
+ } else if (writable.destroyed) {
327
+ return;
328
+ }
329
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
330
+ }
329
331
  var buildOutgoingHttpHeaders = (headers) => {
330
332
  const res = {};
331
333
  if (!(headers instanceof Headers)) {
@@ -367,8 +369,6 @@ global.fetch = (info, init) => {
367
369
 
368
370
  // src/listener.ts
369
371
  var outgoingEnded = Symbol("outgoingEnded");
370
- var regBuffer = /^no$/i;
371
- var regContentType = /^(application\/json\b|text\/(?!event-stream\b))/i;
372
372
  var handleRequestError = () => new Response(null, {
373
373
  status: 400
374
374
  });
@@ -440,23 +440,48 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
440
440
  }
441
441
  const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
442
442
  if (res.body) {
443
- const {
444
- "transfer-encoding": transferEncoding,
445
- "content-encoding": contentEncoding,
446
- "content-length": contentLength,
447
- "x-accel-buffering": accelBuffering,
448
- "content-type": contentType
449
- } = resHeaderRecord;
450
- if (transferEncoding || contentEncoding || contentLength || // nginx buffering variant
451
- accelBuffering && regBuffer.test(accelBuffering) || !regContentType.test(contentType)) {
452
- outgoing.writeHead(res.status, resHeaderRecord);
453
- flushHeaders(outgoing);
454
- await writeFromReadableStream(res.body, outgoing);
443
+ const reader = res.body.getReader();
444
+ const values = [];
445
+ let done = false;
446
+ let currentReadPromise = void 0;
447
+ for (let i = 0; i < 2; i++) {
448
+ currentReadPromise = reader.read();
449
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
450
+ console.error(e);
451
+ done = true;
452
+ });
453
+ if (!chunk) {
454
+ if (i === 1 && resHeaderRecord["transfer-encoding"] !== "chunked") {
455
+ await new Promise((resolve) => setTimeout(resolve));
456
+ i--;
457
+ continue;
458
+ }
459
+ break;
460
+ }
461
+ currentReadPromise = void 0;
462
+ if (chunk.value) {
463
+ values.push(chunk.value);
464
+ }
465
+ if (chunk.done) {
466
+ done = true;
467
+ break;
468
+ }
469
+ }
470
+ if (done && !("content-length" in resHeaderRecord)) {
471
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
472
+ }
473
+ outgoing.writeHead(res.status, resHeaderRecord);
474
+ values.forEach((value) => {
475
+ ;
476
+ outgoing.write(value);
477
+ });
478
+ if (done) {
479
+ outgoing.end();
455
480
  } else {
456
- const buffer = await res.arrayBuffer();
457
- resHeaderRecord["content-length"] = buffer.byteLength;
458
- outgoing.writeHead(res.status, resHeaderRecord);
459
- outgoing.end(new Uint8Array(buffer));
481
+ if (values.length === 0) {
482
+ flushHeaders(outgoing);
483
+ }
484
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
460
485
  }
461
486
  } else if (resHeaderRecord[X_ALREADY_SENT]) {
462
487
  } else {
package/dist/server.mjs CHANGED
@@ -252,30 +252,24 @@ Object.setPrototypeOf(Response2, GlobalResponse);
252
252
  Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
253
253
 
254
254
  // src/utils.ts
255
- function writeFromReadableStream(stream, writable) {
256
- if (stream.locked) {
257
- throw new TypeError("ReadableStream is locked.");
258
- } else if (writable.destroyed) {
259
- stream.cancel();
260
- return;
261
- }
262
- const reader = stream.getReader();
263
- writable.on("close", cancel);
264
- writable.on("error", cancel);
265
- reader.read().then(flow, cancel);
255
+ async function readWithoutBlocking(readPromise) {
256
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
257
+ }
258
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
259
+ const handleError = () => {
260
+ };
261
+ writable.on("error", handleError);
262
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
266
263
  return reader.closed.finally(() => {
267
- writable.off("close", cancel);
268
- writable.off("error", cancel);
264
+ writable.off("error", handleError);
269
265
  });
270
- function cancel(error) {
271
- reader.cancel(error).catch(() => {
272
- });
266
+ function handleStreamError(error) {
273
267
  if (error) {
274
268
  writable.destroy(error);
275
269
  }
276
270
  }
277
271
  function onDrain() {
278
- reader.read().then(flow, cancel);
272
+ reader.read().then(flow, handleStreamError);
279
273
  }
280
274
  function flow({ done, value }) {
281
275
  try {
@@ -284,13 +278,21 @@ function writeFromReadableStream(stream, writable) {
284
278
  } else if (!writable.write(value)) {
285
279
  writable.once("drain", onDrain);
286
280
  } else {
287
- return reader.read().then(flow, cancel);
281
+ return reader.read().then(flow, handleStreamError);
288
282
  }
289
283
  } catch (e) {
290
- cancel(e);
284
+ handleStreamError(e);
291
285
  }
292
286
  }
293
287
  }
288
+ function writeFromReadableStream(stream, writable) {
289
+ if (stream.locked) {
290
+ throw new TypeError("ReadableStream is locked.");
291
+ } else if (writable.destroyed) {
292
+ return;
293
+ }
294
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
295
+ }
294
296
  var buildOutgoingHttpHeaders = (headers) => {
295
297
  const res = {};
296
298
  if (!(headers instanceof Headers)) {
@@ -332,8 +334,6 @@ global.fetch = (info, init) => {
332
334
 
333
335
  // src/listener.ts
334
336
  var outgoingEnded = Symbol("outgoingEnded");
335
- var regBuffer = /^no$/i;
336
- var regContentType = /^(application\/json\b|text\/(?!event-stream\b))/i;
337
337
  var handleRequestError = () => new Response(null, {
338
338
  status: 400
339
339
  });
@@ -405,23 +405,48 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
405
405
  }
406
406
  const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
407
407
  if (res.body) {
408
- const {
409
- "transfer-encoding": transferEncoding,
410
- "content-encoding": contentEncoding,
411
- "content-length": contentLength,
412
- "x-accel-buffering": accelBuffering,
413
- "content-type": contentType
414
- } = resHeaderRecord;
415
- if (transferEncoding || contentEncoding || contentLength || // nginx buffering variant
416
- accelBuffering && regBuffer.test(accelBuffering) || !regContentType.test(contentType)) {
417
- outgoing.writeHead(res.status, resHeaderRecord);
418
- flushHeaders(outgoing);
419
- await writeFromReadableStream(res.body, outgoing);
408
+ const reader = res.body.getReader();
409
+ const values = [];
410
+ let done = false;
411
+ let currentReadPromise = void 0;
412
+ for (let i = 0; i < 2; i++) {
413
+ currentReadPromise = reader.read();
414
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
415
+ console.error(e);
416
+ done = true;
417
+ });
418
+ if (!chunk) {
419
+ if (i === 1 && resHeaderRecord["transfer-encoding"] !== "chunked") {
420
+ await new Promise((resolve) => setTimeout(resolve));
421
+ i--;
422
+ continue;
423
+ }
424
+ break;
425
+ }
426
+ currentReadPromise = void 0;
427
+ if (chunk.value) {
428
+ values.push(chunk.value);
429
+ }
430
+ if (chunk.done) {
431
+ done = true;
432
+ break;
433
+ }
434
+ }
435
+ if (done && !("content-length" in resHeaderRecord)) {
436
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
437
+ }
438
+ outgoing.writeHead(res.status, resHeaderRecord);
439
+ values.forEach((value) => {
440
+ ;
441
+ outgoing.write(value);
442
+ });
443
+ if (done) {
444
+ outgoing.end();
420
445
  } else {
421
- const buffer = await res.arrayBuffer();
422
- resHeaderRecord["content-length"] = buffer.byteLength;
423
- outgoing.writeHead(res.status, resHeaderRecord);
424
- outgoing.end(new Uint8Array(buffer));
446
+ if (values.length === 0) {
447
+ flushHeaders(outgoing);
448
+ }
449
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
425
450
  }
426
451
  } else if (resHeaderRecord[X_ALREADY_SENT]) {
427
452
  } else {
package/dist/utils.d.mts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { OutgoingHttpHeaders } from 'node:http';
2
2
  import { Writable } from 'node:stream';
3
3
 
4
+ declare function readWithoutBlocking(readPromise: Promise<ReadableStreamReadResult<Uint8Array>>): Promise<ReadableStreamReadResult<Uint8Array> | undefined>;
5
+ declare function writeFromReadableStreamDefaultReader(reader: ReadableStreamDefaultReader<Uint8Array>, writable: Writable, currentReadPromise?: Promise<ReadableStreamReadResult<Uint8Array>> | undefined): Promise<undefined>;
4
6
  declare function writeFromReadableStream(stream: ReadableStream<Uint8Array>, writable: Writable): Promise<undefined> | undefined;
5
7
  declare const buildOutgoingHttpHeaders: (headers: Headers | HeadersInit | null | undefined) => OutgoingHttpHeaders;
6
8
 
7
- export { buildOutgoingHttpHeaders, writeFromReadableStream };
9
+ export { buildOutgoingHttpHeaders, readWithoutBlocking, writeFromReadableStream, writeFromReadableStreamDefaultReader };
package/dist/utils.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { OutgoingHttpHeaders } from 'node:http';
2
2
  import { Writable } from 'node:stream';
3
3
 
4
+ declare function readWithoutBlocking(readPromise: Promise<ReadableStreamReadResult<Uint8Array>>): Promise<ReadableStreamReadResult<Uint8Array> | undefined>;
5
+ declare function writeFromReadableStreamDefaultReader(reader: ReadableStreamDefaultReader<Uint8Array>, writable: Writable, currentReadPromise?: Promise<ReadableStreamReadResult<Uint8Array>> | undefined): Promise<undefined>;
4
6
  declare function writeFromReadableStream(stream: ReadableStream<Uint8Array>, writable: Writable): Promise<undefined> | undefined;
5
7
  declare const buildOutgoingHttpHeaders: (headers: Headers | HeadersInit | null | undefined) => OutgoingHttpHeaders;
6
8
 
7
- export { buildOutgoingHttpHeaders, writeFromReadableStream };
9
+ export { buildOutgoingHttpHeaders, readWithoutBlocking, writeFromReadableStream, writeFromReadableStreamDefaultReader };
package/dist/utils.js CHANGED
@@ -21,33 +21,29 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var utils_exports = {};
22
22
  __export(utils_exports, {
23
23
  buildOutgoingHttpHeaders: () => buildOutgoingHttpHeaders,
24
- writeFromReadableStream: () => writeFromReadableStream
24
+ readWithoutBlocking: () => readWithoutBlocking,
25
+ writeFromReadableStream: () => writeFromReadableStream,
26
+ writeFromReadableStreamDefaultReader: () => writeFromReadableStreamDefaultReader
25
27
  });
26
28
  module.exports = __toCommonJS(utils_exports);
27
- function writeFromReadableStream(stream, writable) {
28
- if (stream.locked) {
29
- throw new TypeError("ReadableStream is locked.");
30
- } else if (writable.destroyed) {
31
- stream.cancel();
32
- return;
33
- }
34
- const reader = stream.getReader();
35
- writable.on("close", cancel);
36
- writable.on("error", cancel);
37
- reader.read().then(flow, cancel);
29
+ async function readWithoutBlocking(readPromise) {
30
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
31
+ }
32
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
33
+ const handleError = () => {
34
+ };
35
+ writable.on("error", handleError);
36
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
38
37
  return reader.closed.finally(() => {
39
- writable.off("close", cancel);
40
- writable.off("error", cancel);
38
+ writable.off("error", handleError);
41
39
  });
42
- function cancel(error) {
43
- reader.cancel(error).catch(() => {
44
- });
40
+ function handleStreamError(error) {
45
41
  if (error) {
46
42
  writable.destroy(error);
47
43
  }
48
44
  }
49
45
  function onDrain() {
50
- reader.read().then(flow, cancel);
46
+ reader.read().then(flow, handleStreamError);
51
47
  }
52
48
  function flow({ done, value }) {
53
49
  try {
@@ -56,13 +52,21 @@ function writeFromReadableStream(stream, writable) {
56
52
  } else if (!writable.write(value)) {
57
53
  writable.once("drain", onDrain);
58
54
  } else {
59
- return reader.read().then(flow, cancel);
55
+ return reader.read().then(flow, handleStreamError);
60
56
  }
61
57
  } catch (e) {
62
- cancel(e);
58
+ handleStreamError(e);
63
59
  }
64
60
  }
65
61
  }
62
+ function writeFromReadableStream(stream, writable) {
63
+ if (stream.locked) {
64
+ throw new TypeError("ReadableStream is locked.");
65
+ } else if (writable.destroyed) {
66
+ return;
67
+ }
68
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
69
+ }
66
70
  var buildOutgoingHttpHeaders = (headers) => {
67
71
  const res = {};
68
72
  if (!(headers instanceof Headers)) {
@@ -85,5 +89,7 @@ var buildOutgoingHttpHeaders = (headers) => {
85
89
  // Annotate the CommonJS export names for ESM import in node:
86
90
  0 && (module.exports = {
87
91
  buildOutgoingHttpHeaders,
88
- writeFromReadableStream
92
+ readWithoutBlocking,
93
+ writeFromReadableStream,
94
+ writeFromReadableStreamDefaultReader
89
95
  });
package/dist/utils.mjs CHANGED
@@ -1,28 +1,22 @@
1
1
  // src/utils.ts
2
- function writeFromReadableStream(stream, writable) {
3
- if (stream.locked) {
4
- throw new TypeError("ReadableStream is locked.");
5
- } else if (writable.destroyed) {
6
- stream.cancel();
7
- return;
8
- }
9
- const reader = stream.getReader();
10
- writable.on("close", cancel);
11
- writable.on("error", cancel);
12
- reader.read().then(flow, cancel);
2
+ async function readWithoutBlocking(readPromise) {
3
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
4
+ }
5
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
6
+ const handleError = () => {
7
+ };
8
+ writable.on("error", handleError);
9
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
13
10
  return reader.closed.finally(() => {
14
- writable.off("close", cancel);
15
- writable.off("error", cancel);
11
+ writable.off("error", handleError);
16
12
  });
17
- function cancel(error) {
18
- reader.cancel(error).catch(() => {
19
- });
13
+ function handleStreamError(error) {
20
14
  if (error) {
21
15
  writable.destroy(error);
22
16
  }
23
17
  }
24
18
  function onDrain() {
25
- reader.read().then(flow, cancel);
19
+ reader.read().then(flow, handleStreamError);
26
20
  }
27
21
  function flow({ done, value }) {
28
22
  try {
@@ -31,13 +25,21 @@ function writeFromReadableStream(stream, writable) {
31
25
  } else if (!writable.write(value)) {
32
26
  writable.once("drain", onDrain);
33
27
  } else {
34
- return reader.read().then(flow, cancel);
28
+ return reader.read().then(flow, handleStreamError);
35
29
  }
36
30
  } catch (e) {
37
- cancel(e);
31
+ handleStreamError(e);
38
32
  }
39
33
  }
40
34
  }
35
+ function writeFromReadableStream(stream, writable) {
36
+ if (stream.locked) {
37
+ throw new TypeError("ReadableStream is locked.");
38
+ } else if (writable.destroyed) {
39
+ return;
40
+ }
41
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
42
+ }
41
43
  var buildOutgoingHttpHeaders = (headers) => {
42
44
  const res = {};
43
45
  if (!(headers instanceof Headers)) {
@@ -59,5 +61,7 @@ var buildOutgoingHttpHeaders = (headers) => {
59
61
  };
60
62
  export {
61
63
  buildOutgoingHttpHeaders,
62
- writeFromReadableStream
64
+ readWithoutBlocking,
65
+ writeFromReadableStream,
66
+ writeFromReadableStreamDefaultReader
63
67
  };
package/dist/vercel.js CHANGED
@@ -285,30 +285,24 @@ Object.setPrototypeOf(Response2, GlobalResponse);
285
285
  Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
286
286
 
287
287
  // src/utils.ts
288
- function writeFromReadableStream(stream, writable) {
289
- if (stream.locked) {
290
- throw new TypeError("ReadableStream is locked.");
291
- } else if (writable.destroyed) {
292
- stream.cancel();
293
- return;
294
- }
295
- const reader = stream.getReader();
296
- writable.on("close", cancel);
297
- writable.on("error", cancel);
298
- reader.read().then(flow, cancel);
288
+ async function readWithoutBlocking(readPromise) {
289
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
290
+ }
291
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
292
+ const handleError = () => {
293
+ };
294
+ writable.on("error", handleError);
295
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
299
296
  return reader.closed.finally(() => {
300
- writable.off("close", cancel);
301
- writable.off("error", cancel);
297
+ writable.off("error", handleError);
302
298
  });
303
- function cancel(error) {
304
- reader.cancel(error).catch(() => {
305
- });
299
+ function handleStreamError(error) {
306
300
  if (error) {
307
301
  writable.destroy(error);
308
302
  }
309
303
  }
310
304
  function onDrain() {
311
- reader.read().then(flow, cancel);
305
+ reader.read().then(flow, handleStreamError);
312
306
  }
313
307
  function flow({ done, value }) {
314
308
  try {
@@ -317,13 +311,21 @@ function writeFromReadableStream(stream, writable) {
317
311
  } else if (!writable.write(value)) {
318
312
  writable.once("drain", onDrain);
319
313
  } else {
320
- return reader.read().then(flow, cancel);
314
+ return reader.read().then(flow, handleStreamError);
321
315
  }
322
316
  } catch (e) {
323
- cancel(e);
317
+ handleStreamError(e);
324
318
  }
325
319
  }
326
320
  }
321
+ function writeFromReadableStream(stream, writable) {
322
+ if (stream.locked) {
323
+ throw new TypeError("ReadableStream is locked.");
324
+ } else if (writable.destroyed) {
325
+ return;
326
+ }
327
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
328
+ }
327
329
  var buildOutgoingHttpHeaders = (headers) => {
328
330
  const res = {};
329
331
  if (!(headers instanceof Headers)) {
@@ -365,8 +367,6 @@ global.fetch = (info, init) => {
365
367
 
366
368
  // src/listener.ts
367
369
  var outgoingEnded = Symbol("outgoingEnded");
368
- var regBuffer = /^no$/i;
369
- var regContentType = /^(application\/json\b|text\/(?!event-stream\b))/i;
370
370
  var handleRequestError = () => new Response(null, {
371
371
  status: 400
372
372
  });
@@ -438,23 +438,48 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
438
438
  }
439
439
  const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
440
440
  if (res.body) {
441
- const {
442
- "transfer-encoding": transferEncoding,
443
- "content-encoding": contentEncoding,
444
- "content-length": contentLength,
445
- "x-accel-buffering": accelBuffering,
446
- "content-type": contentType
447
- } = resHeaderRecord;
448
- if (transferEncoding || contentEncoding || contentLength || // nginx buffering variant
449
- accelBuffering && regBuffer.test(accelBuffering) || !regContentType.test(contentType)) {
450
- outgoing.writeHead(res.status, resHeaderRecord);
451
- flushHeaders(outgoing);
452
- await writeFromReadableStream(res.body, outgoing);
441
+ const reader = res.body.getReader();
442
+ const values = [];
443
+ let done = false;
444
+ let currentReadPromise = void 0;
445
+ for (let i = 0; i < 2; i++) {
446
+ currentReadPromise = reader.read();
447
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
448
+ console.error(e);
449
+ done = true;
450
+ });
451
+ if (!chunk) {
452
+ if (i === 1 && resHeaderRecord["transfer-encoding"] !== "chunked") {
453
+ await new Promise((resolve) => setTimeout(resolve));
454
+ i--;
455
+ continue;
456
+ }
457
+ break;
458
+ }
459
+ currentReadPromise = void 0;
460
+ if (chunk.value) {
461
+ values.push(chunk.value);
462
+ }
463
+ if (chunk.done) {
464
+ done = true;
465
+ break;
466
+ }
467
+ }
468
+ if (done && !("content-length" in resHeaderRecord)) {
469
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
470
+ }
471
+ outgoing.writeHead(res.status, resHeaderRecord);
472
+ values.forEach((value) => {
473
+ ;
474
+ outgoing.write(value);
475
+ });
476
+ if (done) {
477
+ outgoing.end();
453
478
  } else {
454
- const buffer = await res.arrayBuffer();
455
- resHeaderRecord["content-length"] = buffer.byteLength;
456
- outgoing.writeHead(res.status, resHeaderRecord);
457
- outgoing.end(new Uint8Array(buffer));
479
+ if (values.length === 0) {
480
+ flushHeaders(outgoing);
481
+ }
482
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
458
483
  }
459
484
  } else if (resHeaderRecord[X_ALREADY_SENT]) {
460
485
  } else {