Skip to content

Commit d2cb418

Browse files
committed
feat(dev-overrides): Add automatic response cleanup via onClose callback
changeset changeset
1 parent 042dfd9 commit d2cb418

File tree

5 files changed

+42
-1
lines changed

5 files changed

+42
-1
lines changed

.changeset/eleven-moose-heal.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
fix(dev-overrides): Add automatic response cleanup via onClose callback

packages/open-next/src/http/openNextResponse.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ export class OpenNextNodeResponse extends Transform implements ServerResponse {
8484
) {
8585
this.statusCode = statusCode;
8686
}
87+
88+
// We want to destroy this response when the original response is closed. (i.e when the client disconnects)
89+
// This is to support `request.signal.onabort` in route handlers
90+
if (streamCreator?.onClose) {
91+
streamCreator.onClose(() => {
92+
this.destroy();
93+
});
94+
}
8795
}
8896

8997
// Necessary for next 12

packages/open-next/src/overrides/wrappers/express-dev.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const wrapper: WrapperHandler = async (handler, converter) => {
4141
req.headers["x-forwarded-proto"] = req.protocol;
4242
}
4343
const internalEvent = await converter.convertFrom(req);
44+
45+
let onCloseCallback: (() => void) | undefined;
4446
const streamCreator: StreamCreator = {
4547
writeHeaders: (prelude) => {
4648
res.setHeader("Set-Cookie", prelude.cookies);
@@ -49,7 +51,17 @@ const wrapper: WrapperHandler = async (handler, converter) => {
4951
return res;
5052
},
5153
onFinish: () => {},
54+
onClose: (callback) => {
55+
onCloseCallback = callback;
56+
},
5257
};
58+
59+
res.on("close", () => {
60+
if (onCloseCallback) {
61+
onCloseCallback();
62+
}
63+
});
64+
5365
await handler(internalEvent, { streamCreator });
5466
});
5567

packages/open-next/src/overrides/wrappers/node.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,35 @@ import { debug, error } from "../../adapters/logger";
88
const wrapper: WrapperHandler = async (handler, converter) => {
99
const server = createServer(async (req, res) => {
1010
const internalEvent = await converter.convertFrom(req);
11+
12+
let onCloseCallback: (() => void) | undefined;
1113
const streamCreator: StreamCreator = {
1214
writeHeaders: (prelude) => {
1315
res.setHeader("Set-Cookie", prelude.cookies);
1416
res.writeHead(prelude.statusCode, prelude.headers);
1517
res.flushHeaders();
1618
return res;
1719
},
20+
onClose: (callback) => {
21+
onCloseCallback = callback;
22+
},
1823
};
24+
25+
res.on("close", () => {
26+
if (onCloseCallback) {
27+
onCloseCallback();
28+
}
29+
});
30+
1931
if (internalEvent.rawPath === "/__health") {
2032
res.writeHead(200, {
2133
"Content-Type": "text/plain",
2234
});
2335
res.end("OK");
2436
} else {
25-
await handler(internalEvent, { streamCreator });
37+
await handler(internalEvent, {
38+
streamCreator,
39+
});
2640
}
2741
});
2842

packages/open-next/src/types/open-next.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export interface StreamCreator {
4949
// Just to fix an issue with aws lambda streaming with empty body
5050
onWrite?: () => void;
5151
onFinish?: (length: number) => void;
52+
// This is called when the wrappers response is closed, i.e. when the client disconnects
53+
onClose?: (callback: () => void) => void;
5254
}
5355

5456
export type WaitUntil = (promise: Promise<void>) => void;

0 commit comments

Comments
 (0)