Skip to content

Commit 9c781b0

Browse files
committed
Fix graceful shutdown test hanging
The test was passing but the process never exited because a 30-second fallback timer in shutdown() was never cancelled when shutdownResolve() was called early. Fixed by: - Saving the timeout ID when creating the fallback timer - Clearing the timeout when shutdownResolve() is called This ensures the JS event loop can complete after shutdown finishes.
1 parent 4a78272 commit 9c781b0

16 files changed

Lines changed: 1710 additions & 0 deletions

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,9 @@ hex = "0.4"
3838

3939
# File watching
4040
notify = { version = "6.1", default-features = false, features = ["macos_fsevent"] }
41+
42+
# HTTP server
43+
hyper = { version = "1.0", features = ["server", "http1"] }
44+
hyper-util = { version = "0.1", features = ["tokio", "server", "server-auto"] }
45+
http-body-util = "0.1"
46+
bytes = "1.0"

funee-lib/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,3 +654,15 @@ export type {
654654
} from "./watcher/index.ts";
655655

656656
export { watchFile, watchDirectory } from "./watcher/index.ts";
657+
658+
// ============================================================================
659+
// HTTP Server - Deno-style serve() API
660+
// ============================================================================
661+
662+
export type {
663+
RequestHandler,
664+
ServeOptions,
665+
Server,
666+
} from "./server/index.ts";
667+
668+
export { serve } from "./server/index.ts";

funee-lib/server/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* HTTP Server Module
3+
*
4+
* Provides serve() function for creating HTTP servers.
5+
*/
6+
7+
export type {
8+
RequestHandler,
9+
ServeOptions,
10+
Server,
11+
} from "./serve.ts";
12+
13+
export { serve } from "./serve.ts";

funee-lib/server/serve.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* HTTP Server - serve() function types
3+
*
4+
* The actual implementation is in the runtime bootstrap (run_js.rs).
5+
* This file exports types for TypeScript users.
6+
*
7+
* @example
8+
* ```typescript
9+
* import { serve } from "funee";
10+
*
11+
* // Simple server
12+
* const server = serve({ port: 3000 }, (req) => {
13+
* return new Response("Hello, World!");
14+
* });
15+
*
16+
* // Shutdown when done
17+
* await server.shutdown();
18+
* ```
19+
*/
20+
21+
/**
22+
* Request handler function
23+
*/
24+
export type RequestHandler = (request: Request) => Response | Promise<Response>;
25+
26+
/**
27+
* Options for serve()
28+
*/
29+
export type ServeOptions = {
30+
/** Port to listen on. Use 0 for random available port. */
31+
port: number;
32+
/** Hostname to bind to. Default: "127.0.0.1" */
33+
hostname?: string;
34+
/** Called when server starts listening */
35+
onListen?: (info: { port: number; hostname: string }) => void;
36+
/** Called when handler throws an error */
37+
onError?: (error: Error) => Response | Promise<Response>;
38+
};
39+
40+
/**
41+
* Server handle returned by serve()
42+
*/
43+
export type Server = {
44+
/** Port the server is listening on */
45+
readonly port: number;
46+
/** Hostname the server is bound to */
47+
readonly hostname: string;
48+
/** Gracefully shutdown the server */
49+
shutdown: () => Promise<void>;
50+
};
51+
52+
// Declare the global serve function (provided by runtime bootstrap)
53+
declare global {
54+
function serve(
55+
options: ServeOptions,
56+
handler: RequestHandler,
57+
): Server;
58+
}
59+
60+
/**
61+
* Create an HTTP server
62+
*
63+
* @param options - Server options including port and callbacks
64+
* @param handler - Request handler function
65+
* @returns Server handle with shutdown method
66+
*
67+
* @example
68+
* ```typescript
69+
* const server = serve({ port: 3000 }, (req) => {
70+
* const url = new URL(req.url);
71+
* if (url.pathname === "/api") {
72+
* return Response.json({ hello: "world" });
73+
* }
74+
* return new Response("Not Found", { status: 404 });
75+
* });
76+
* ```
77+
*/
78+
export const serve: (
79+
options: ServeOptions,
80+
handler: RequestHandler,
81+
) => Server = globalThis.serve;

0 commit comments

Comments
 (0)