Adapters for integrating H3 with different JavaScript runtimes and deployment platforms including Node.js, Web standards, and legacy systems.
Convert H3 applications to work with Node.js HTTP servers and Connect-style middleware.
/**
* Convert H3 app to Node.js HTTP handler
* @param app - H3 application instance
* @returns Node.js HTTP request handler
*/
function toNodeHandler(app: H3): NodeHandler;
/**
* Convert Node.js handler to H3 event handler
* @param handler - Node.js handler or middleware
* @returns H3 event handler
*/
function fromNodeHandler(handler: NodeHandler | NodeMiddleware): EventHandler;
/**
* Define Node.js HTTP handler
* @param handler - Node.js handler function
* @returns Node.js handler function
*/
function defineNodeHandler(handler: NodeHandler): NodeHandler;
/**
* Define Node.js middleware
* @param handler - Node.js middleware function
* @returns Node.js middleware function
*/
function defineNodeMiddleware(handler: NodeMiddleware): NodeMiddleware;Usage Examples:
import { H3, toNodeHandler, fromNodeHandler } from "h3";
import { createServer } from "http";
import express from "express";
// Convert H3 to Node.js
const app = new H3();
app.get("/", () => ({ message: "Hello from H3" }));
app.post("/users", async (event) => {
const body = await readBody(event);
return { user: body };
});
// Create Node.js server
const nodeHandler = toNodeHandler(app);
const server = createServer(nodeHandler);
server.listen(3000);
// Use with Express
const expressApp = express();
expressApp.use("/api", nodeHandler);
expressApp.listen(3001);
// Convert Express middleware to H3
const expressMiddleware = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
const h3Middleware = fromNodeHandler(expressMiddleware);
app.use(h3Middleware);
// Legacy Connect middleware
const connectMiddleware = (req, res, next) => {
res.setHeader("X-Powered-By", "H3");
next();
};
app.use(fromNodeHandler(connectMiddleware));Convert between H3 and Web API standard handlers (Fetch API).
/**
* Convert H3 app to Web API handler (Deprecated - use app.fetch instead)
* @param app - H3 application instance
* @returns Web API fetch handler
*/
function toWebHandler(app: H3): (
request: ServerRequest,
context?: H3EventContext
) => Promise<Response>;
/**
* Convert Web API handler to H3 event handler
* @param handler - Web API fetch handler
* @returns H3 event handler
*/
function fromWebHandler(
handler: (request: ServerRequest, context?: H3EventContext) => Promise<Response>
): EventHandler;Usage Examples:
import { H3, fromWebHandler } from "h3";
// Use Web API handler in H3
const webApiHandler = async (request: Request) => {
const url = new URL(request.url);
if (url.pathname === "/api/time") {
return new Response(JSON.stringify({ time: Date.now() }), {
headers: { "Content-Type": "application/json" }
});
}
return new Response("Not Found", { status: 404 });
};
const app = new H3();
app.use("/web-api", fromWebHandler(webApiHandler));
// Convert existing fetch handler
const fetchHandler = async (request: Request, context?: any) => {
const body = await request.json();
return new Response(JSON.stringify({ received: body }), {
headers: { "Content-Type": "application/json" }
});
};
app.post("/fetch-handler", fromWebHandler(fetchHandler));
// Use H3 with Cloudflare Workers
export default {
async fetch(request: Request, env: any, ctx: any): Promise<Response> {
const app = new H3();
app.get("/worker", () => ({
message: "Hello from Cloudflare Worker",
env: env.ENVIRONMENT
}));
return await app.fetch(request, { env, ctx });
}
};
// Use with Deno
import { serve } from "https://deno.land/std/http/server.ts";
const app = new H3();
app.get("/deno", () => ({ runtime: "Deno", version: Deno.version.deno }));
serve((request) => app.fetch(request), { port: 8000 });Adapt behavior based on the JavaScript runtime environment.
// Runtime detection patterns
const runtimeAwareHandler = defineHandler((event) => {
const runtime = event.runtime;
switch (runtime?.name) {
case "node":
return handleNodeJs(event);
case "deno":
return handleDeno(event);
case "bun":
return handleBun(event);
case "cloudflare":
return handleCloudflareWorkers(event);
case "workerd":
return handleWorkerd(event);
default:
return handleGeneric(event);
}
});Usage Examples:
// Platform-specific features
const platformHandler = defineHandler((event) => {
const platform = event.runtime?.platform || "unknown";
const features = {
filesystem: ["node", "deno", "bun"].includes(platform),
crypto: true, // Available in all modern runtimes
streams: true,
workers: platform === "cloudflare"
};
return { platform, features };
});
// Environment-specific configuration
const configHandler = defineHandler((event) => {
const runtime = event.runtime?.name || "generic";
const config = {
node: {
port: process.env.PORT || 3000,
workers: require("os").cpus().length
},
deno: {
port: Deno.env.get("PORT") || 8000,
permissions: Deno.permissions
},
bun: {
port: process.env.PORT || 3000,
version: Bun.version
},
cloudflare: {
region: event.context.cf?.colo,
country: event.context.cf?.country
}
};
return config[runtime] || { runtime: "generic" };
});import { H3, toNodeHandler } from "h3";
import { createServer } from "http";
import cluster from "cluster";
import { cpus } from "os";
// Create H3 app
const app = new H3();
// Routes
app.get("/", () => ({ message: "Node.js + H3" }));
app.get("/health", () => ({ status: "healthy", pid: process.pid }));
// Cluster setup
if (cluster.isPrimary) {
const numCPUs = cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", (worker) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork();
});
} else {
const server = createServer(toNodeHandler(app));
const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log(`Worker ${process.pid} listening on port ${port}`);
});
}import { H3 } from "h3/cloudflare";
const app = new H3();
app.get("/", () => ({
message: "Hello from Cloudflare Workers",
location: "Edge"
}));
app.get("/geo", (event) => ({
country: event.context.cf?.country,
city: event.context.cf?.city,
timezone: event.context.cf?.timezone
}));
app.post("/kv", async (event) => {
const { key, value } = await readBody(event);
await event.context.env.MY_KV.put(key, value);
return { stored: true };
});
export default {
async fetch(request: Request, env: any, ctx: any): Promise<Response> {
return await app.fetch(request, { env, ctx, cf: request.cf });
}
};import { H3 } from "h3/deno";
import { serve } from "https://deno.land/std/http/server.ts";
const app = new H3();
app.get("/", () => ({
message: "Hello from Deno",
version: Deno.version.deno
}));
app.get("/file/:filename", async (event) => {
const filename = getRouterParam(event, "filename");
try {
const content = await Deno.readTextFile(`./files/${filename}`);
return { filename, content };
} catch (error) {
throw HTTPError.status(404, "File not found");
}
});
// Start server
serve((request) => app.fetch(request), {
port: parseInt(Deno.env.get("PORT") || "8000")
});import { H3 } from "h3/bun";
const app = new H3();
app.get("/", () => ({
message: "Hello from Bun",
version: Bun.version
}));
app.post("/upload", async (event) => {
const formData = await readBody(event);
const file = formData.get("file") as File;
if (file) {
await Bun.write(`./uploads/${file.name}`, file);
return { uploaded: file.name, size: file.size };
}
throw HTTPError.status(400, "No file provided");
});
// Start Bun server
Bun.serve({
port: process.env.PORT || 3000,
fetch: (request) => app.fetch(request)
});import { H3 } from "h3/service-worker";
const app = new H3();
app.get("/sw", () => ({
message: "Hello from Service Worker",
scope: self.registration?.scope
}));
app.get("/cache/:key", async (event) => {
const key = getRouterParam(event, "key");
const cache = await caches.open("api-cache");
const response = await cache.match(`/data/${key}`);
if (response) {
return await response.json();
}
throw HTTPError.status(404, "Not in cache");
});
// Service Worker event handlers
self.addEventListener("fetch", (event) => {
if (event.request.url.includes("/api/")) {
event.respondWith(app.fetch(event.request));
}
});/**
* Node.js HTTP handler type
*/
type NodeHandler = (
req: IncomingMessage,
res: ServerResponse
) => void | Promise<void>;
/**
* Node.js middleware type
*/
type NodeMiddleware = (
req: IncomingMessage,
res: ServerResponse,
next: (error?: any) => void
) => void | Promise<void>;/**
* Server runtime context
*/
interface ServerRuntimeContext {
/**
* Runtime name (node, deno, bun, cloudflare, etc.)
*/
name?: string;
/**
* Runtime version
*/
version?: string;
/**
* Platform information
*/
platform?: string;
/**
* Additional runtime-specific data
*/
[key: string]: any;
}
/**
* Cloudflare-specific context
*/
interface CloudflareContext {
/**
* Cloudflare environment variables
*/
env: {
[key: string]: any;
};
/**
* Execution context
*/
ctx: {
waitUntil: (promise: Promise<any>) => void;
passThroughOnException: () => void;
};
/**
* Request CF properties
*/
cf?: {
country?: string;
city?: string;
region?: string;
timezone?: string;
colo?: string;
[key: string]: any;
};
}Create bridges between different middleware ecosystems.
// Express to H3 bridge
function expressToH3(expressMiddleware: any) {
return defineMiddleware(async (event) => {
return new Promise((resolve, reject) => {
const req = event.req as any;
const res = event.res as any;
// Add Express-like methods
res.json = (data: any) => {
event.res.setHeader("Content-Type", "application/json");
return JSON.stringify(data);
};
res.status = (code: number) => {
event.res.setStatus(code);
return res;
};
expressMiddleware(req, res, (error?: any) => {
if (error) reject(error);
else resolve();
});
});
});
}
// Koa to H3 bridge
function koaToH3(koaMiddleware: any) {
return defineMiddleware(async (event) => {
const ctx = {
request: event.req,
response: event.res,
state: event.context
};
await koaMiddleware(ctx, async () => {});
});
}Runtime-specific optimizations.
// Runtime-optimized handlers
const optimizedHandler = defineHandler((event) => {
const runtime = event.runtime?.name;
switch (runtime) {
case "bun":
// Use Bun-specific optimizations
return handleWithBunOptimizations(event);
case "node":
// Use Node.js-specific optimizations
return handleWithNodeOptimizations(event);
case "cloudflare":
// Use edge-specific optimizations
return handleWithEdgeOptimizations(event);
default:
return handleGeneric(event);
}
});