Documentation

HTTP Server

Understand how Frame-Master's HTTP server works, built on top of Bun's blazing-fast server implementation. Learn about request handling, routing, and server lifecycle.

Overview

Frame-Master uses Bun.serve() as its underlying HTTP server, providing exceptional performance while adding a powerful plugin system and request management layer.

💡

Built on Bun

Frame-Master leverages Bun's HTTP server, which is written in Zig and offers industry-leading performance. Frame-Master adds a plugin architecture, request routing, and developer-friendly utilities on top of this foundation.

Server Architecture

architecture
sequenceDiagram participant Client as HTTP Client participant Bun as Bun.serve Runtime participant Master as masterRequest Handler participant Plugins as Plugin System participant Logger as Request Logger Client->>Bun: Incoming HTTP Request activate Bun Bun->>Master: Forward Request activate Master Note over Master: Parse URL, Headers, Context rect rgb(30, 41, 59) Note right of Master: Phase 1: Pre-processing Master->>Plugins: Execute before_request hooks activate Plugins Plugins-->>Master: Hook Results deactivate Plugins Master->>Master: Setup Request Context end rect rgb(15, 23, 42) Note right of Master: Phase 2: Request Handling Master->>Plugins: Execute request hooks activate Plugins Plugins->>Plugins: request plugin Logic Plugins-->>Master: Response Data deactivate Plugins end rect rgb(20, 30, 48) Note right of Master: Phase 2.5: HTML Rewriting alt Response is ReadableStream or String alt Injection Authorized Master->>Master: Inject Global Values end alt HTML Rewriting Authorized Master->>Plugins: Execute HTMLRewrite hooks activate Plugins Plugins->>Plugins: Transform HTML Content Plugins-->>Master: Rewritten HTML end deactivate Plugins end end rect rgb(30, 41, 59) Note right of Master: Phase 3: Post-processing Master->>Plugins: Execute after_request hooks activate Plugins Plugins-->>Master: Modified Response deactivate Plugins Master->>Master: Inject Cookies Master->>Master: Add/Modify Headers end Master->>Bun: Final Response activate Logger Bun->>Logger: Log Request alt Logging Authorized Logger->>Logger: Log Method & Path end Logger-->>Bun: Logging Complete deactivate Logger deactivate Master Bun->>Client: HTTP Response deactivate Bun

Server Initialization

Frame-Master initializes the HTTP server through a multi-stage process that loads plugins, merges configurations, and sets up request handling.

Startup Sequence

1. Configuration Loading

Frame-Master loads your frame-master.config.ts file and validates the configuration.

2. Plugin Initialization

All plugins in the plugins array are loaded and initialized in order.

3. Server Config Merging

Plugin serverConfig hooks are merged with your HTTPServer configuration using a deep merge strategy.

4. Server Start Hooks

Plugin serverStart hooks run, allowing plugins to perform initialization tasks.

5. File System Watchers (Development)

In development mode, file watchers are set up for hot reloading and plugin file watching.

6. Bun.serve() Start

Finally, Bun.serve() is called with the merged configuration and Frame-Master's fetch handler.

Server Initialization Code

server/index.ts
export default async () => {
// Run plugin serverStart hooks
await runOnStartMainPlugins();
// Setup file watchers (dev mode only)
await runFileSystemWatcherPlugin();
// Start the HTTP server
return Bun.serve({
development: {
chromeDevToolsAutomaticWorkspaceFolders: true,
},
...pluginServerConfig,
fetch: (request, server) => {
logRequest(request);
const reqManager = new masterRequest({ request, server });
return reqManager.handleRequest();
},
routes: { ...masterRoutes, ...pluginsRoutes },
websocket: { /* WebSocket handlers */ },
});
};

Configuration Merging

Frame-Master uses a deep merge strategy to combine server configurations from multiple sources:

⚠️

Configuration Conflicts

If multiple plugins set the same server option with different values (e.g., different ports), Frame-Master will throw an error unless you disable the warning with disableHttpServerOptionsConflictWarning.

Route Handling

Frame-Master supports multiple types of routes: static routes defined in configuration and dynamic routes managed by plugins.

Static Routes

Define static routes in your configuration for simple endpoints:

frame-master.config.ts
const config: FrameMasterConfig = {
HTTPServer: {
port: 3000,
// Static routes (Bun native routing)
routes: {
"/api/health": () => Response.json({ status: "ok" }),
"/api/version": () => Response.json({
version: "1.0.0",
framework: "Frame-Master"
}),
},
},
plugins: [
{
name: "example-plugin",
version: "1.0.0",
serverConfig: {
// Static routes (Bun native routing)
routes: {
"/api/plugin-info": () => Response.json({}),
},
}
}
],
};
💡

Bun Routes

These routes use Bun's native routing, which is extremely fast but limited in functionality. For more complex routing, use plugins.

Plugin Routes

Plugins provide their own routes through the serverConfig hook:

plugin-routes.ts
const myPlugin: FrameMasterPlugin = {
name: "my-api-plugin",
version: "1.0.0",
serverConfig: {
routes: {
"/api/custom": () => Response.json({
message: "From plugin"
}),
},
},
// Or use the request hook for complex routing
router: {
request(master) {
if (master.pathname === "/api/complex") {
master.setResponse(
JSON.stringify({ data: "Complex logic" }),
{ headers: { "Content-Type": "application/json" } }
);
}
},
},
};

Route Priority

Routes are merged and matched in this order:

1.Plugin routes (first plugin's routes have priority)
2.Your HTTPServer config routes (can override plugin routes)
3.masterRequest handler (fallback to plugin request hooks)

WebSocket Support

Frame-Master provides built-in WebSocket support through Bun's WebSocket implementation with plugin integration.

websocket-config.ts
const config: FrameMasterConfig = {
HTTPServer: {
port: 3000,
websocket: {
maxPayloadLength: 16 * 1024 * 1024, // 16MB
idleTimeout: 120, // seconds
backpressureLimit: 1024 * 1024, // 1MB
perMessageDeflate: true,
},
},
plugins: [],
};

Plugin WebSocket Handlers

Plugins can hook into WebSocket events:

websocket-plugin.ts
const wsPlugin: FrameMasterPlugin = {
name: "websocket-plugin",
version: "1.0.0",
serverConfig: {
routes: {
"/ws/my-identifier": (req, server) => {
const res = server.upgrade(req as Request, {
data: { id: "my-identifier" },
});
if (!res)
return Response.json(
{ error: "WebSocket upgrade failed" },
{ status: 400 }
);
return new Response("ok", { status: 101 });
},
},
} as Partial<Bun.Serve.Options<{ id: string }>>
websocket: {
onOpen(ws) {
const data = ws.data as unknown as { id: string };
if(data.id === "my-identifier") {
console.log("WebSocket with my-identifier opened");
ws.send("Welcome, my-identifier!");
} else {
console.log("WebSocket opened with unknown identifier");
ws.send("Welcome, unknown identifier!");
}
},
onMessage(ws, message) {
const data = ws.data as unknown as { id: string };
if(data.id !== "my-identifier") return;
console.log("Received:", message);
ws.send(`Echo: ${message}`);
},
onClose(ws) {
const data = ws.data as unknown as { id: string };
if(data.id !== "my-identifier") return;
console.log("WebSocket closed");
},
},
};
💡

Learn More

For detailed WebSocket documentation, see Bun's WebSocket guide.

Development Features

Frame-Master includes several development-only features to improve the developer experience.

Hot Module Reload (HMR)

When running in development mode with bun --hot frame-master dev, Frame-Master provides hot reloading:

🔥

Server Hot Reload

Bun automatically restarts the server when code changes are detected

🔄

Plugin File Watching

Plugins can watch specific directories and trigger custom rebuild logic

Fast Restarts

Bun's hot reload is extremely fast, typically under 100ms

terminal
# Start with hot reload
bun --hot frame-master dev
# Or via package.json script
bun run dev

File System Watchers

Plugins can register directories to watch for changes:

file-watcher.ts
const myPlugin: FrameMasterPlugin = {
name: "my-plugin",
version: "1.0.0",
// Specify directories to watch
fileSystemWatchDir: ["src/pages", "src/components"],
// Handle file changes
onFileSystemChange(event, file, absolutePath) {
console.log(`${event}: ${file}`);
if (event === "change" && file.endsWith(".tsx")) {
// Trigger rebuild or processing
rebuildComponent(absolutePath);
}
},
};
⚠️

Production Mode

File watchers are automatically disabled in production mode (NODE_ENV=production)

Best Practices

🔧

Configure Development Mode

Set development: true in HTTPServer config during development for better error messages and debugging

📝

Use Request Logging Wisely

Disable verbose logging in production to reduce noise and improve performance

🔌

Organize Plugin Order

Place plugins that modify requests early in the array, and response-modifying plugins later

Optimize Hot Paths

Keep plugin request hooks fast - avoid synchronous I/O or heavy computation

🛡️

Handle Errors Gracefully

Implement custom error handlers to provide better user experience and security

External Resources

Learn more about the underlying technologies and APIs.

Bun HTTP Server Documentation

Complete guide to Bun's HTTP server implementation

Bun WebSocket Documentation

Learn about WebSocket support in Bun

Bun Routing Documentation

Understand Bun's native routing capabilities

MDN Web Request API

Reference for the standard Web Request object

Next Steps

Continue learning about Frame-Master's core functionality.