Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit e94713d

Browse files
committed
Require Response return for Durable Object fetches
1 parent c9e4aa5 commit e94713d

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

packages/durable-objects/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
"dependencies": {
3939
"@miniflare/core": "2.0.0-next.3",
4040
"@miniflare/shared": "2.0.0-next.3",
41-
"@miniflare/storage-memory": "2.0.0-next.3"
41+
"@miniflare/storage-memory": "2.0.0-next.3",
42+
"undici": "^4.9.3"
4243
},
4344
"devDependencies": {
4445
"@miniflare/shared-test": "2.0.0-next.3"

packages/durable-objects/src/namespace.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
withInputGating,
1010
} from "@miniflare/core";
1111
import { Awaitable, Context, InputGate, OutputGate } from "@miniflare/shared";
12+
import { Response as BaseResponse } from "undici";
13+
import { DurableObjectError } from "./plugin";
1214
import { DurableObjectStorage } from "./storage";
1315

1416
function hexEncode(value: Uint8Array): string {
@@ -107,7 +109,21 @@ export class DurableObjectStub {
107109
// noinspection SuspiciousTypeOfGuard
108110
const request =
109111
input instanceof Request && !init ? input : new Request(input, init);
110-
return state[kFetch](withInputGating(withImmutableHeaders(request)));
112+
const res = await state[kFetch](
113+
withInputGating(withImmutableHeaders(request))
114+
);
115+
116+
// noinspection SuspiciousTypeOfGuard
117+
const validRes =
118+
res instanceof Response || (res as any) instanceof BaseResponse;
119+
if (!validRes) {
120+
throw new DurableObjectError(
121+
"ERR_RESPONSE_TYPE",
122+
"Durable Object fetch handler didn't respond with a Response object"
123+
);
124+
}
125+
126+
return res;
111127
}
112128
}
113129

packages/durable-objects/src/plugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ interface ProcessedDurableObject {
3737
scriptName?: string;
3838
}
3939

40-
export type DurableObjectErrorCode = "ERR_CLASS_NOT_FOUND"; // Missing constructor for object
40+
export type DurableObjectErrorCode =
41+
| "ERR_CLASS_NOT_FOUND" // Missing constructor for object
42+
| "ERR_RESPONSE_TYPE"; // Fetch handler returned non-Response object;
4143

4244
export class DurableObjectError extends MiniflareError<DurableObjectErrorCode> {}
4345

packages/durable-objects/test/namespace.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { deserialize } from "v8";
33
import { Request, Response, fetch } from "@miniflare/core";
44
import {
55
DurableObject,
6+
DurableObjectError,
67
DurableObjectId,
78
DurableObjectNamespace,
89
DurableObjectState,
@@ -207,6 +208,29 @@ test("DurableObjectStub: fetch: passes through web socket requests", async (t) =
207208
webSocket.send("test message");
208209
t.is(await dataPromise, "test message");
209210
});
211+
test("DurableObjectStub: fetch: throws if handler doesn't return Response", async (t) => {
212+
const factory = new MemoryStorageFactory();
213+
const plugin = new DurableObjectsPlugin(log, compat, {
214+
durableObjects: { TEST: "TestObject" },
215+
});
216+
217+
class TestObject implements DurableObject {
218+
fetch(): Response {
219+
return "definitely a response" as any;
220+
}
221+
}
222+
plugin.beforeReload();
223+
plugin.reload({ TestObject }, {});
224+
225+
const ns = plugin.getNamespace(factory, "TEST");
226+
const stub = ns.get(testId);
227+
await t.throwsAsync(stub.fetch("http://localhost"), {
228+
instanceOf: DurableObjectError,
229+
code: "ERR_RESPONSE_TYPE",
230+
message:
231+
"Durable Object fetch handler didn't respond with a Response object",
232+
});
233+
});
210234
test("DurableObjectStub: hides implementation details", async (t) => {
211235
const [ns] = getTestObjectNamespace();
212236
const stub = ns.get(testId);

0 commit comments

Comments
 (0)