Hono Integration
The @bext/hono package provides a Hono middleware that injects bext services into your request context, plus a standalone client for use outside of request handlers.
Installation
npm install @bext/hono
# or
bun add @bext/hono
Peer dependencies: hono >= 4.0.0
Middleware
Add the middleware to inject c.var.bext into all handlers:
const app = new Hono();
// Add bext services to all routes
app.use(bextMiddleware());
app.post("/api/products", async (c) => {
const product = await createProduct(c.req.json());
// Invalidate cached product pages
await c.var.bext.cache.invalidateTag("products");
// Notify connected clients
await c.var.bext.realtime.publish("products", { action: "created", product });
return c.json(product, 201);
});
export default app;
Custom Configuration
app.use(bextMiddleware({
baseUrl: "http://127.0.0.1:3061", // SDK sidecar URL
appId: "my-app", // App identifier for multi-app isolation
}));
Standalone Client
For use outside of request handlers (scripts, workers, etc.):
const bext = createBextClient();
// Same API as c.var.bext
await bext.cache.invalidateTag("products");
await bext.realtime.publish("updates", { type: "deploy" });
await bext.kv.set("config:feature-flags", { darkMode: true });
API Reference
BextClient
interface BextClient {
cache: BextCache;
realtime: BextRealtime;
kv: BextKv;
queue: BextQueue;
tasks: BextTasks;
}
Cache
interface BextCache {
invalidateTag(tag: string): Promise<void>;
invalidatePath(path: string): Promise<void>;
}
Real-Time
interface BextRealtime {
publish(topic: string, data: unknown): Promise<void>;
}
KV Store
interface BextKv {
get(key: string): Promise;
set(key: string, value: unknown, opts?: { ttl?: number }): Promise<void>;
delete(key: string): Promise<void>;
}
Queues
interface BextQueue {
push(name: string, payload: unknown, opts?: { delay?: number }): Promise<void>;
pull(name: string): Promise<QueueMessage | null>;
ack(name: string, id: string): Promise<void>;
}
interface QueueMessage {
id: string;
data: T;
attempts: number;
}
Tasks
interface BextTasks {
register(name: string, definition: { cron: string; command: string }): Promise<void>;
list(): Promise<TaskInfo[]>;
cancel(name: string): Promise<void>;
}
interface TaskInfo {
name: string;
cron: string;
command: string;
registeredAt: number;
lastRun: number | null;
}
Example: Full CRUD with Caching
const app = new Hono();
app.use(bextMiddleware());
// List products (ISR-cached by bext, invalidated on mutation)
app.get("/api/products", async (c) => {
const products = await db.products.findMany();
return c.json(products);
});
// Create product — invalidate cache + push event
app.post("/api/products", async (c) => {
const data = await c.req.json();
const product = await db.products.create(data);
await c.var.bext.cache.invalidateTag("products");
await c.var.bext.realtime.publish("products", { action: "created", id: product.id });
return c.json(product, 201);
});
// Delete product — invalidate + event + queue cleanup job
app.delete("/api/products/:id", async (c) => {
const id = c.req.param("id");
await db.products.delete(id);
await c.var.bext.cache.invalidateTag("products");
await c.var.bext.cache.invalidatePath(`/products/${id}`);
await c.var.bext.realtime.publish("products", { action: "deleted", id });
await c.var.bext.queue.push("cleanup", { type: "product-assets", productId: id });
return c.json({ deleted: true });
});
export default app;