
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 Bun-native, HTML-first framework that renders real pages, treats UI frameworks as renderers, and makes SEO the default.
A Bun-native, HTML-first framework that renders real pages, treats UI frameworks as renderers, and makes SEO the default—not a feature.
KilatJS is a server-first web framework inspired by the simplicity of PHP and the power of modern component libraries. It rejects the complexity of SPAs, hydration, and client-side routing in favor of real HTML rendered on the server.
"Request → Load → Render HTML → Response. That's it."
The easiest way to start is using the KilatJS CLI:
# Create a new project in my-app folder
bunx kilat create my-app
cd my-app
bun install
bun run dev
Visit http://localhost:3000 🎉
| Command | Description |
|---|---|
kilat create [dir] | Create a new project from template |
kilat dev | Start development server with HMR + Live Reload |
kilat build | Build for production |
kilat serve | Run production server (bun dist/server.js) |
kilat preview | Preview build output |
⚡ KilatJS Dev Server
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
➜ http://localhost:3000
➜ HMR + Live Reload enabled
➜ Edit files and see changes instantly
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
KilatJS uses a simplified, root-level structure:
my-app/
├── public/ # Static assets & index.html
├── routes/ # SSR routes (index.tsx, about.tsx)
├── components/ # React/Kilat components
├── kilat.config.ts # Configuration
├── input.css # Tailwind input
├── index.client.tsx # (Optional) React client entry
├── App.tsx # (Optional) Client-side app
└── dist/ # Production build
While KilatJS is HTML-first, you can easily add a full React client-side application for complex interactive features.
index.client.tsx exists in your root, KilatJS will automatically bundle it.public/index.html with a mount point:<div id="root"></div>
<script type="module" src="/client/index.client.js"></script>
clientRoute: "/client" in kilat.config.ts to host your SPA.Each route file can export:
// SEO meta tags
export const meta = {
title: "Page Title",
description: "Page description",
robots: "index,follow",
ogTitle: "Open Graph Title",
ogDescription: "OG description",
ogImage: "https://example.com/image.jpg",
};
// Server-side data loading
export async function load(ctx) {
const data = await fetchData();
return { items: data };
}
// HTTP method handlers (POST, PUT, DELETE, etc.)
export async function POST(ctx) {
const formData = await ctx.request.formData();
// Process form...
return Response.redirect("/success", 302);
}
// Page component (receives data from load())
export default function Page({ data, params, state }) {
return (
<div>
{data.items.map((item) => (
<p>{item.name}</p>
))}
</div>
);
}
src/components/Layout.tsx:
interface LayoutProps {
children: React.ReactNode;
title?: string;
}
export function Layout({ children, title = "My Blog" }: LayoutProps) {
return (
<div className="min-h-screen bg-gray-50">
<header className="bg-white shadow">
<nav className="max-w-4xl mx-auto px-4 py-4">
<a href="/" className="text-xl font-bold">
My Blog
</a>
<div className="float-right space-x-4">
<a href="/" className="text-gray-600 hover:text-gray-900">
Home
</a>
<a href="/blog" className="text-gray-600 hover:text-gray-900">
Blog
</a>
<a href="/about" className="text-gray-600 hover:text-gray-900">
About
</a>
</div>
</nav>
</header>
<main className="max-w-4xl mx-auto px-4 py-8">{children}</main>
</div>
);
}
src/routes/blog/index.tsx:
import { Layout } from "../../components/Layout";
export const meta = {
title: "Blog - My Site",
description: "Read our latest articles",
};
export async function load() {
// In real app, fetch from database
const posts = [
{
id: 1,
slug: "hello-world",
title: "Hello World",
excerpt: "My first post...",
},
{
id: 2,
slug: "getting-started",
title: "Getting Started",
excerpt: "Learn how to...",
},
];
return { posts };
}
export default function BlogPage({ data }) {
return (
<Layout>
<h1 className="text-3xl font-bold mb-8">Blog</h1>
<div className="space-y-6">
{data.posts.map((post) => (
<article key={post.id} className="bg-white p-6 rounded-lg shadow">
<h2 className="text-xl font-semibold">
<a href={`/blog/${post.slug}`} className="hover:text-blue-600">
{post.title}
</a>
</h2>
<p className="text-gray-600 mt-2">{post.excerpt}</p>
</article>
))}
</div>
</Layout>
);
}
src/routes/blog/[slug].tsx:
import { Layout } from "../../components/Layout";
export const meta = {
title: "Blog Post",
description: "Read this article",
};
export async function load({ params }) {
// params.slug contains the URL parameter
const post = await getPostBySlug(params.slug);
if (!post) {
throw new Response("Not Found", { status: 404 });
}
return { post };
}
async function getPostBySlug(slug: string) {
// In real app, fetch from database
const posts = {
"hello-world": { title: "Hello World", content: "This is my first post!" },
"getting-started": {
title: "Getting Started",
content: "Let me show you how...",
},
};
return posts[slug] || null;
}
export default function BlogPostPage({ data, params }) {
return (
<Layout>
<article>
<h1 className="text-4xl font-bold mb-4">{data.post.title}</h1>
<div className="prose max-w-none">{data.post.content}</div>
</article>
<a href="/blog" className="text-blue-600 mt-8 inline-block">
← Back to Blog
</a>
</Layout>
);
}
src/routes/api/posts.ts:
import { RouteContext } from "kilatjs";
const posts = [
{ id: 1, title: "Hello World", slug: "hello-world" },
{ id: 2, title: "Getting Started", slug: "getting-started" },
];
// GET /api/posts
export async function GET(ctx: RouteContext) {
const search = ctx.query.get("search")?.toLowerCase();
let results = posts;
if (search) {
results = posts.filter((p) => p.title.toLowerCase().includes(search));
}
return new Response(JSON.stringify({ data: results }), {
headers: { "Content-Type": "application/json" },
});
}
// POST /api/posts
export async function POST(ctx: RouteContext) {
const body = await ctx.request.json();
const newPost = {
id: posts.length + 1,
title: body.title,
slug: body.title.toLowerCase().replace(/\s+/g, "-"),
};
posts.push(newPost);
return new Response(JSON.stringify({ data: newPost }), {
status: 201,
headers: { "Content-Type": "application/json" },
});
}
/**
* NEW: Standalone API Mode with Swagger Documentation
* KilatJS provides a dedicated core for building pure APIs.
*/
// example/server.ts
import KilatJS, { swagger, RouteContext } from "kilatjs/core";
const app = new KilatJS();
// Register Swagger documentation
app.use(
swagger(app, {
path: "/docs",
title: "KilatJS API",
description: "Automatic API documentation",
})
);
// Route with metadata for Swagger
app.post(
"/api/echo",
{
summary: "Echo request",
body: { text: "string" }, // Optional: for documentation
response: { echo: {}, receivedAt: "string" }, // Optional: for documentation
},
async (ctx: RouteContext) => {
const body = await ctx.request.json();
return { echo: body, receivedAt: new Date() };
}
);
app.listen(4000);
src/routes/contact.tsx:
import { Layout } from "../components/Layout";
export const meta = {
title: "Contact Us",
description: "Get in touch with us",
};
// Handle form submission
export async function POST({ request }) {
const formData = await request.formData();
const name = formData.get("name");
const email = formData.get("email");
const message = formData.get("message");
// Save to database, send email, etc.
console.log("Contact form:", { name, email, message });
// PRG: Post-Redirect-Get pattern
return Response.redirect("/contact/success", 302);
}
export default function ContactPage() {
return (
<Layout>
<h1 className="text-3xl font-bold mb-8">Contact Us</h1>
<form method="POST" className="max-w-md space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Name</label>
<input
type="text"
name="name"
required
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Email</label>
<input
type="email"
name="email"
required
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Message</label>
<textarea
name="message"
rows={4}
required
className="w-full px-3 py-2 border rounded-lg"
/>
</div>
<button
type="submit"
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700"
>
Send Message
</button>
</form>
</Layout>
);
}
src/routes/contact/success.tsx:
import { Layout } from "../../components/Layout";
export const meta = {
title: "Message Sent",
};
export default function ContactSuccessPage() {
return (
<Layout>
<div className="text-center py-12">
<h1 className="text-3xl font-bold text-green-600 mb-4">
✓ Message Sent!
</h1>
<p className="text-gray-600 mb-8">
Thank you for contacting us. We'll get back to you soon.
</p>
<a href="/" className="text-blue-600 hover:underline">
← Back to Home
</a>
</div>
</Layout>
);
}
// src/routes/dashboard.tsx
export async function load({ request }) {
const cookie = request.headers.get("cookie");
const session = await getSession(cookie);
if (!session) {
// Redirect to login if not authenticated
throw Response.redirect("/login", 302);
}
return { user: session.user };
}
export default function DashboardPage({ data }) {
return (
<div>
<h1>Welcome, {data.user.name}!</h1>
<form method="POST" action="/logout">
<button type="submit">Logout</button>
</form>
</div>
);
}
// kilat.config.ts
import { defineConfig } from "kilatjs";
export default defineConfig({
appDir: "./src", // Source directory (auto-detects routes/ or pages/)
outDir: "./dist", // Production build output
port: 3000, // Server port
hostname: "localhost", // Server hostname
publicDir: "./public", // Static assets directory
tailwind: {
enabled: true, // Enable Tailwind CSS
inputPath: "./input.css",
cssPath: "./styles.css",
},
});
KilatJS leverages Bun's runtime directly:
Performance:
KilatJS is server-first, but you can add client-side interactivity using these patterns:
clientScript Export (Recommended)Export a function that runs in the browser. TypeScript/LSP fully supports it!
// src/routes/counter.tsx
// Client-side script - auto-injected, LSP checks the code!
export function clientScript() {
let count = 0;
const countEl = document.getElementById("count")!;
document.getElementById("decrement")!.onclick = () => {
countEl.textContent = String(--count);
};
document.getElementById("increment")!.onclick = () => {
countEl.textContent = String(++count);
};
}
export default function CounterPage() {
return (
<div>
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
</div>
);
}
The framework automatically injects the script - no manual <script> tags needed!
Lightweight reactivity with declarative HTML attributes:
export default function AlpinePage() {
return (
<div x-data="{ count: 0 }">
<button x-on:click="count--">-</button>
<span x-text="count">0</span>
<button x-on:click="count++">+</button>
</div>
);
}
Server-driven UI updates without JavaScript:
<!-- Can use .html files directly in routes/ -->
<button hx-get="/api/greeting" hx-target="#result" hx-swap="innerHTML">
Load
</button>
<div id="result"></div>
KilatJS supports .html files as routes - perfect for HTMX pages!
Best for mutations - no JS required:
<form method="POST" action="/contact">
<input name="email" type="email" />
<button type="submit">Submit</button>
</form>
// kilat.config.ts
import { defineConfig } from "kilatjs";
export default defineConfig({
appDir: ".", // Root directory for routes/ and components/
outDir: "./dist", // Production build output
port: 3000, // Server port
publicDir: "./public", // Static assets directory (auto-detects index.html)
clientRoute: "/client", // (Optional) Path for React client SPA
tailwind: {
enabled: true, // Enable Tailwind CSS
inputPath: "./input.css",
cssPath: "./public/styles.css",
},
});
KilatJS uniquely allows you to mix HTML-First SSR with Full React CSR:
Note: KilatJS keeps these worlds separate. SSR pages are pure HTML (no React runtime), while CSR pages are full React apps. This gives you the speed of a static site with the power of a modern app.
KilatJS provides a dedicated core for building pure JSON APIs with automatic documentation.
swagger middleware to generate interactive documentation.RouteOptions to provide metadata, request bodies, and response structures.KilatJS core for JSON-first services.import KilatJS, { swagger, RouteContext } from "kilatjs/core";
const app = new KilatJS();
app.use(
swagger(app, {
path: "/docs",
title: "My API Documentation",
})
);
app.get(
"/api/users",
{
summary: "List users",
response: { users: [] },
},
(ctx) => {
return { users: ["Alice", "Bob"] };
}
);
app.listen(4000);
MIT
Built with 💜 for the real web using Bun.
FAQs
A Bun-native, HTML-first framework that renders real pages, treats UI frameworks as renderers, and makes SEO the default.
We found that kilatjs 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.