
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A fast, lightweight web framework for Bun with built-in Zod validation and lifecycle hooks.
bun install
import BXO from "./src/index";
import { cors } from "./plugins";
const app = new BXO();
// Use CORS plugin
app.use(cors());
// Define routes
app.get("/", (ctx) => ctx.json({ message: "Hello World!" }));
app.start();
BXO provides built-in WebSocket support with a clean, intuitive API:
import BXO from "./src";
const app = new BXO();
// WebSocket route
app.ws("/ws", {
open(ws) {
console.log("WebSocket connection opened");
ws.send("Welcome to BXO WebSocket!");
},
message(ws, message) {
console.log("Received message:", message);
// Echo the message back
ws.send(`Echo: ${message}`);
},
close(ws, code, reason) {
console.log(`WebSocket connection closed: ${code} ${reason}`);
},
ping(ws, data) {
console.log("Ping received:", data);
},
pong(ws, data) {
console.log("Pong received:", data);
}
});
// WebSocket with path parameters
app.ws("/chat/:room", {
open(ws) {
const room = ws.data?.room || 'unknown';
console.log(`WebSocket connection opened for room: ${room}`);
ws.send(`Welcome to chat room: ${room}`);
},
message(ws, message) {
const room = ws.data?.room || 'unknown';
console.log(`Message in room ${room}:`, message);
ws.send(`[${room}] Echo: ${message}`);
}
});
app.start();
open(ws) - Called when a WebSocket connection is establishedmessage(ws, message) - Called when a message is receivedclose(ws, code, reason) - Called when the connection is closeddrain(ws) - Called when the WebSocket is ready for more dataping(ws, data) - Called when a ping is receivedpong(ws, data) - Called when a pong is received/chat/:roomws.dataBXO provides powerful lifecycle hooks that allow you to intercept and modify requests and responses at different stages:
Runs before any route processing. Can modify the request or return a response to short-circuit processing.
app.beforeRequest(async (req) => {
console.log(`${req.method} ${req.url}`);
return req; // Continue with request
});
Runs after route processing but before the response is sent. Can modify the final response.
app.afterRequest(async (req, res) => {
res.headers.set("X-Response-Time", Date.now().toString());
return res;
});
Runs after the route handler but before response headers are merged. Useful for modifying response metadata.
app.beforeResponse(async (res) => {
res.headers.set("X-Custom-Header", "value");
return res;
});
Runs when an error occurs during request processing. Can return a custom error response.
app.onError(async (error, req) => {
console.error(`Error: ${error.message}`);
return new Response("Internal Server Error", { status: 500 });
});
The CORS plugin provides comprehensive Cross-Origin Resource Sharing support:
import { cors } from "./plugins";
app.use(cors({
origin: ["http://localhost:3000", "https://myapp.com"],
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true
}));
The OpenAPI plugin automatically generates OpenAPI 3.0 documentation with support for tags, security schemes, and comprehensive route metadata:
import { openapi } from "./plugins";
app.use(openapi({
path: "/docs", // Swagger UI endpoint
jsonPath: "/openapi.json", // OpenAPI JSON endpoint
defaultTags: ["API"], // Default tags for routes
securitySchemes: { // Define security schemes
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
description: "JWT token for authentication"
},
apiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key",
description: "API key for authentication"
}
},
globalSecurity: [ // Global security requirements
{ bearerAuth: [] },
{ apiKeyAuth: [] }
],
openapiConfig: { // Additional OpenAPI config
info: {
title: "My API",
version: "1.0.0",
description: "API description"
}
}
}));
Routes can include detailed metadata for better OpenAPI documentation:
app.get("/users/:id", (ctx) => {
const id = ctx.params.id
return { user: { id, name: "John Doe" } }
}, {
detail: {
tags: ["Users"], // Route tags for grouping
summary: "Get user by ID", // Operation summary
description: "Retrieve user details", // Detailed description
security: [{ bearerAuth: [] }], // Route-specific security
params: { // Parameter documentation
id: z.string().describe("User ID")
}
}
})
tags: Array of tags for grouping operationssummary: Short description of the operationdescription: Detailed description of the operationsecurity: Security requirements for the routeparams: Path parameter schemas and descriptionsquery: Query parameter schemashidden: Set to true to exclude from OpenAPI docsPlugins are just BXO instances with lifecycle hooks:
function loggingPlugin() {
const plugin = new BXO();
plugin.beforeRequest(async (req) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
return req;
});
return plugin;
}
app.use(loggingPlugin());
Define Zod schemas for request validation:
import { z } from "bxo";
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email()
});
app.post("/users", async (ctx) => {
const user = ctx.body; // Already validated by UserSchema
return ctx.json({ id: 1, ...user });
}, {
body: UserSchema
});
BXO automatically parses multipart/form-data into nested objects and arrays before Zod validation:
Form fields like profile[name] are automatically converted to nested objects:
const UserFormSchema = z.object({
name: z.string(),
email: z.string().email(),
profile: z.object({
name: z.string()
})
});
app.post("/users", async (ctx) => {
// Form data: profile[name]="John" becomes { profile: { name: "John" } }
console.log(ctx.body); // { name: "...", email: "...", profile: { name: "John" } }
return ctx.json({ success: true, data: ctx.body });
}, {
body: UserFormSchema
});
Form fields like items[0], items[1] are automatically converted to arrays:
const ItemsSchema = z.object({
items: z.array(z.string()),
tags: z.array(z.string()),
profile: z.object({
name: z.string(),
age: z.string().transform(val => parseInt(val, 10))
})
});
app.post("/items", async (ctx) => {
// Form data: items[0]="Apple", items[1]="Banana" becomes { items: ["Apple", "Banana"] }
console.log(ctx.body); // { items: ["Apple", "Banana"], tags: [...], profile: {...} }
return ctx.json({ success: true, data: ctx.body });
}, {
body: ItemsSchema
});
Form fields like workspace_items[0][id], workspace_items[0][type] are automatically converted to arrays of objects:
const WorkspaceSchema = z.object({
id: z.string(),
workspace_items: z.array(z.object({
id: z.string(),
type: z.string(),
value: z.string(),
options: z.string(),
label: z.string()
}))
});
app.post("/workspace", async (ctx) => {
// Form data: workspace_items[0][id]="item1", workspace_items[0][type]="Link"
// becomes { workspace_items: [{ id: "item1", type: "Link", ... }] }
console.log(ctx.body); // { id: "...", workspace_items: [{ id: "item1", type: "Link", ... }] }
return ctx.json({ success: true, data: ctx.body });
}, {
body: WorkspaceSchema
});
profile[name], settings[theme] → { profile: { name: "..." }, settings: { theme: "..." } }items[0], items[1] → { items: ["...", "..."] }workspace_items[0][id], workspace_items[0][type] → { workspace_items: [{ id: "...", type: "..." }] }{ tags: ["tag1", "tag2"] }bun run ./src/index.ts
Or run the examples:
# CORS example
bun run ./example/cors-example.ts
# Multipart form data parsing example
bun run ./example/multipart-example.ts
Check out the example/ directory for more usage examples:
cors-example.ts - Demonstrates CORS plugin and lifecycle hooksopenapi-example.ts - Demonstrates OpenAPI plugin with tags and securitywebsocket-example.ts - Demonstrates WebSocket functionality with interactive HTML clientmultipart-example.ts - Demonstrates multipart/form-data parsing with nested objects and arraysindex.ts - Basic routing exampleThis project was created using bun init in bun v1.2.3. Bun is a fast all-in-one JavaScript runtime.
FAQs
Unknown package
The npm package bxo receives a total of 47 weekly downloads. As such, bxo popularity was classified as not popular.
We found that bxo demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.