@warp-drive/holodeck 0.1.0-alpha.82 → 0.1.0-alpha.83

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@warp-drive/holodeck",
3
3
  "description": "⚡️ Simple, Fast HTTP Mocking for Tests",
4
- "version": "0.1.0-alpha.82",
4
+ "version": "0.1.0-alpha.83",
5
5
  "license": "MIT",
6
6
  "author": "Chris Thoburn <runspired@users.noreply.github.com>",
7
7
  "repository": {
@@ -34,9 +34,9 @@
34
34
  "ensure-cert": "./server/ensure-cert.js"
35
35
  },
36
36
  "peerDependencies": {
37
- "@warp-drive/utilities": "5.10.0-alpha.6",
38
- "@warp-drive/legacy": "5.10.0-alpha.6",
39
- "@warp-drive/core": "5.10.0-alpha.6"
37
+ "@warp-drive/utilities": "5.10.0-alpha.7",
38
+ "@warp-drive/legacy": "5.10.0-alpha.7",
39
+ "@warp-drive/core": "5.10.0-alpha.7"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@warp-drive/utilities": {
@@ -52,10 +52,10 @@
52
52
  "@babel/preset-env": "^7.29.7",
53
53
  "@babel/preset-typescript": "^7.29.7",
54
54
  "@babel/runtime": "^7.29.7",
55
- "@warp-drive/utilities": "5.10.0-alpha.6",
56
- "@warp-drive/legacy": "5.10.0-alpha.6",
57
- "@warp-drive/core": "5.10.0-alpha.6",
58
- "@warp-drive/internal-config": "5.10.0-alpha.6",
55
+ "@warp-drive/utilities": "5.10.0-alpha.7",
56
+ "@warp-drive/legacy": "5.10.0-alpha.7",
57
+ "@warp-drive/core": "5.10.0-alpha.7",
58
+ "@warp-drive/internal-config": "5.10.0-alpha.7",
59
59
  "tsdown": "^0.23.0",
60
60
  "typescript-7": "npm:typescript@7.1.0-dev.20260907.1"
61
61
  },
package/server/bun.js CHANGED
@@ -4,6 +4,7 @@ import { HTTPException } from 'hono/http-exception';
4
4
  import { logger } from 'hono/logger';
5
5
  import fs from 'node:fs';
6
6
  import { createSecureServer } from 'node:http2';
7
+ import { Readable } from 'node:stream';
7
8
  import { styleText } from 'node:util';
8
9
  import { Worker, threadId, parentPort } from 'node:worker_threads';
9
10
  import path from 'path';
@@ -42,10 +43,14 @@ async function replayRequest(context, cacheKey) {
42
43
 
43
44
  try {
44
45
  const bodyPath = `${cacheKey}.body.br`;
45
- const bodyInit = metaJson.status !== 204 && metaJson.status < 500 ? fs.createReadStream(bodyPath) : '';
46
+ // Hand `new Response()` a web stream explicitly, never a Node `Readable` --
47
+ // see the longer note on the same line in ./node.js. A Node stream reaches
48
+ // undici through an adapter whose queued-microtask `close()` races a client
49
+ // abort and can kill this process.
50
+ const bodyInit =
51
+ metaJson.status !== 204 && metaJson.status < 500 ? Readable.toWeb(fs.createReadStream(bodyPath)) : '';
46
52
 
47
53
  const headers = new Headers(metaJson.headers || {});
48
- // @ts-expect-error - createReadStream is supported in node
49
54
  const response = new Response(bodyInit, {
50
55
  status: metaJson.status,
51
56
  statusText: metaJson.statusText,
package/server/node.js CHANGED
@@ -5,6 +5,7 @@ import { HTTPException } from 'hono/http-exception';
5
5
  import { logger } from 'hono/logger';
6
6
  import fs from 'node:fs';
7
7
  import { createSecureServer } from 'node:http2';
8
+ import { Readable } from 'node:stream';
8
9
  import { styleText } from 'node:util';
9
10
  import { Worker, threadId, parentPort } from 'node:worker_threads';
10
11
  import path from 'path';
@@ -43,10 +44,18 @@ async function replayRequest(context, cacheKey) {
43
44
 
44
45
  try {
45
46
  const bodyPath = `${cacheKey}.body.br`;
46
- const bodyInit = metaJson.status !== 204 && metaJson.status < 500 ? fs.createReadStream(bodyPath) : '';
47
+ // Hand `new Response()` a web stream explicitly. Undici treats a Node
48
+ // `Readable` as an async iterable and adapts it into a byte stream whose
49
+ // controller it closes from a queued microtask, so a client that aborts
50
+ // mid-response closes that controller first and the queued `close()` then
51
+ // throws `ERR_INVALID_STATE`. It throws synchronously inside a microtask,
52
+ // so it is an `uncaughtException` -- unreachable by `.catch()` or an
53
+ // `unhandledRejection` handler, and fatal to this process. Do not "fix" a
54
+ // recurrence by installing one; keep the body a real `ReadableStream`.
55
+ const bodyInit =
56
+ metaJson.status !== 204 && metaJson.status < 500 ? Readable.toWeb(fs.createReadStream(bodyPath)) : '';
47
57
 
48
58
  const headers = new Headers(metaJson.headers || {});
49
- // @ts-expect-error - createReadStream is supported in node
50
59
  const response = new Response(bodyInit, {
51
60
  status: metaJson.status,
52
61
  statusText: metaJson.statusText,