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 Logger as Request Logger participant Master as masterRequest Handler participant Plugins as Plugin System Client->>Bun: Incoming HTTP Request activate Bun Bun->>Logger: Forward Request activate Logger Logger->>Logger: Log Method & Path Logger->>Master: Initialize Handler deactivate Logger 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->>Plugins: Match Routes & Extract Params 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: API/SSR/Static 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 Master->>Master: Inject Global Values Master->>Plugins: Execute HTMLRewrite hooks activate Plugins Plugins->>Plugins: Transform HTML Content Plugins-->>Master: Rewritten HTML 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 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:

config-merge.ts
// Merge order (lowest to highest priority):
// 1. Plugin 1 serverConfig
// 2. Plugin 2 serverConfig
// 3. Plugin N serverConfig
// 4. Your HTTPServer config (highest priority)
function deepMergeServerConfig(target: any, source: any): any {
const result = { ...target };
for (const [key, sourceValue] of Object.entries(source)) {
const targetValue = result[key];
// Detect conflicts
if (targetValue !== sourceValue &&
typeof targetValue !== "object") {
throw new Error(`Conflict: ${key} has different values`);
}
// Deep merge objects
if (isPlainObject(targetValue) && isPlainObject(sourceValue)) {
result[key] = deepMergeServerConfig(targetValue, sourceValue);
}
// Concatenate arrays
else if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
result[key] = [...targetValue, ...sourceValue];
}
// Source overrides target
else {
result[key] = sourceValue;
}
}
return result;
}
⚠️

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.

Request Lifecycle

Every HTTP request goes through a structured lifecycle managed by Frame-Master's request manager.

Request Phases

request-flow
flowchart TD A[Incoming Request] --> B[Request Logging] B --> C[masterRequest Initialization] C --> C1[Parse URL & Headers] C1 --> C2[Determine if HTML Request] C2 --> C3[Create Request Context] C3 --> D[Before Request Phase] D --> D1{Plugin before_request Hooks} D1 -->|Continue| E[Route Matching] D1 -->|Early Response| M[Response Sent] E --> E1[Match URL to Routes] E1 --> E2[Extract URL Parameters] E2 --> E3[Load Directive Metadata] E3 --> F[Request Phase] F --> F1[Plugin request Hooks] F1 --> F2[API/SSR/Static Handling] F2 --> F3[Build Response] F3 --> G{Response Type?} G -->|ReadableStream/String| H[HTML Rewrite Phase] G -->|Other| I[After Request Phase] H --> H1[Inject Global Values] H1 --> H2[Plugin HTMLRewrite Hooks] H2 --> H3[Transform HTML Content] H3 --> I I --> I1[Plugin after_request Hooks] I1 --> I2[Inject Cookies] I2 --> I3[Add/Modify Headers] I3 --> I4[Finalize Response] I4 --> M M --> N[Cleanup] N --> N1[Logging if configured] N1 --> N2[Metrics if plugin installed] N2 --> N3[Context Cleanup] N3 --> O[Complete] style A fill:#1e40af,stroke:#3b82f6,stroke-width:3px,color:#fff style D fill:#1e293b,stroke:#334155,stroke-width:2px,color:#94a3b8 style F fill:#0f172a,stroke:#1e293b,stroke-width:2px,color:#94a3b8 style H fill:#14532d,stroke:#166534,stroke-width:2px,color:#bbf7d0 style I fill:#1e293b,stroke:#334155,stroke-width:2px,color:#94a3b8 style M fill:#1e40af,stroke:#3b82f6,stroke-width:3px,color:#fff style O fill:#065f46,stroke:#10b981,stroke-width:3px,color:#fff

Request Manager

The masterRequest class is the core of Frame-Master's request handling:

masterRequest
class masterRequest<ContextType extends Record<string, unknown> = {}> {
// Core properties
public request: Request;
public currentState: RequestState;
public match?: RequestMatch;
public isAskingHTML: boolean;
public URL: URL;
public serverInstance: Bun.Server<undefined>;
public serverConfig: FrameMasterConfig;
// Cookie management
public getCookie<T extends Record<string, unknown>>(
name: string,
encrypted?: boolean
): T | undefined;
public setCookie<T extends Record<string, unknown>>(
name: string,
data: T,
options?: CookieOptions,
dataOptions?: SetDataOptions
): this;
public deleteCookie(
name: string,
options?: DeleteCookieOptions
): this;
// Response management
public setResponse(body: BodyInit | null, init?: ResponseInit): this;
public unsetResponse(): void;
public isResponseSetted(): boolean;
public sendNow(): void;
public get response(): Response | undefined;
// Context management
public setContext<T>(context: T): T;
public getContext<T = ContextType>(): T;
// Global values injection
public setGlobalValues<T extends Partial<typeof globalThis>>(
values: T
): this;
public preventGlobalValuesInjection(): this;
public isGlobalValuesInjectionPrevented(): boolean;
// HTML rewrite control
public preventRewrite(): this;
// Header management
public setHeader(name: string, value: string): this;
// Internal
public async handleRequest(): Promise<Response>;
public async toResponse(): Promise<Response>;
}

Key Properties

📥

request

The original Web Request object from Bun

🔄

currentState

Current phase: before_request, request, or after_request

🌐

isAskingHTML

True if the request Accept header includes text/html (initial page load)

🍪

Cookie Methods

Get, set, and delete cookies with encryption support

📤

Response Methods

Build and send HTTP responses with full control

Request Logging

Frame-Master automatically logs all incoming requests with color-coded HTTP methods:

console-output
GET → /
POST → /api/users
PUT → /api/users/123
DELETE → /api/users/123
PATCH → /api/users/123

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: [],
};
💡

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",
websocket: {
onOpen(ws) {
console.log("WebSocket opened");
ws.send("Welcome!");
},
onMessage(ws, message) {
console.log("Received:", message);
ws.send(`Echo: ${message}`);
},
onClose(ws) {
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

Chrome DevTools

Frame-Master enables Chrome DevTools integration in development mode:

server-start
Bun.serve({
development: {
chromeDevToolsAutomaticWorkspaceFolders: true,
},
// ... rest of config
});

This allows you to debug server-side code using Chrome's DevTools by opening chrome://inspect.

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)

Performance

Frame-Master inherits Bun's exceptional performance characteristics while adding minimal overhead.

Bun's Performance

Frame-Master is built on Bun, which offers industry-leading HTTP server performance

Native Speed

Bun's HTTP server is written in Zig and optimized for throughput

🚀

Low Latency

Minimal request-to-response overhead, typically under 1ms

📈

High Throughput

Can handle thousands of requests per second on modern hardware

💾

Memory Efficient

Lower memory footprint compared to Node.js-based frameworks

Frame-Master Overhead

Frame-Master adds a thin abstraction layer with minimal performance impact

• Request logging: ~0.1ms (disabled in production if desired)

• Plugin hooks: ~0.5ms per hook (depends on plugin logic)

• Cookie parsing/setting: ~0.2ms

• Route matching: ~0.3ms

Total overhead: ~1-2ms per request

💡

Optimization Tips

  • Use Bun's native routes for simple endpoints (fastest)
  • Minimize plugin hooks in the request path
  • Cache expensive operations in plugins
  • Use streaming responses for large payloads
  • Enable compression for text-based responses

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.