Welcome to StarterKit 007 — a world-class, production-ready full-stack framework built with Bun, React, and Tailwind CSS.
This starter kit is designed for developers who want uncompromising performance, strict type safety, and an incredible Developer Experience (DX) out of the box.
At the core of this starter kit is a custom, highly-optimized Function-First RPC API Layer.
The backend (engine/) runs on Bun and uses a custom runtime.ts that automatically turns your plain TypeScript functions into fully typed REST endpoints. No need to write manual Express/Hono controllers or deal with req/res objects for standard business logic.
The frontend (web/) is a React SPA built with Vite. It features a custom File-Based Router and deeply integrates with the backend via a generated React Query wrapper (useEngine).
When you run make generate, an AST (Abstract Syntax Tree) parser scans your engine's src/api folder and generates strict TypeScript definitions, an OpenAPI spec, and an API client for the frontend. All auto-generated files are hidden away in .generated/ folders so your src/ stays pristine.
- Bun installed locally.
bun installStart the full stack (API + Frontend + AST Watcher):
make dev- Frontend:
http://localhost:5173 - Backend:
http://localhost:3000 - OpenAPI Docs:
http://localhost:3000/openapi.json
Format, lint, and typecheck your code using Biome and TypeScript:
make check
make formatTo create a new endpoint, simply export a function from engine/src/api/.
// engine/src/api/v1/system/ping.ts
export function getSystemPing(input?: { verbose?: boolean }) {
return { status: "ok" };
}The generator intelligently assigns HTTP methods based on your function name prefixes:
get...➔GETpost.../create...➔POSTput.../update...➔PUTdelete.../remove...➔DELETE
On the frontend, calling the API is strictly typed based on the HTTP method to prevent standard REST mistakes:
For GET Requests:
You must wrap your payload in a query object.
import { useEngine } from "@/lib/engine";
// ✅ Correct
const data = useEngine("/system/ping", { query: { verbose: true } });
// ❌ TypeScript Error! (Cannot pass body to GET request)
const data = useEngine("/system/ping", { body: { verbose: true } });For POST/PUT Requests:
You must wrap your payload in a body object.
// ✅ Correct
const data = useEngine("/users/create", { body: { name: "Alice" } });The frontend includes a custom file-based router. Create files inside web/src/app/ and they automatically become routes!
web/src/app/page.tsx➔/web/src/app/health/page.tsx➔/healthweb/src/app/users/[id]/page.tsx➔/users/:id
StarterKit 007 includes a highly scalable, multi-session Google OAuth database authentication system.
Authentication state is stored across three tables:
users: Main user profile fields.accounts: Links users to one or more OAuth providers (enabling future provider integrations).sessions: Tracks active session tokens in formatsession_<random_hex>.<version>(e.g.v1).- Temporary Sessions (
.tmp): Supports single-use session tokens (e.g.session_xxxx.tmp) which are automatically and immediately deleted from the database on validation.
- Temporary Sessions (
To authenticate any RPC endpoint, simply import and call requireAuth() inside your API function:
import { requireAuth } from "../../../core/auth/require-auth";
export async function getProtectedData() {
const user = requireAuth(); // Throws 401 Unauthorized if not authenticated
return { secret: "data", email: user.email };
}The request context, authenticated user, and response headers are tracked using Bun's native AsyncLocalStorage during request lifecycles.
On the frontend, use the useAuth() hook to access profile state or trigger logout:
import { useAuth } from "@/lib/auth-context";
export default function MyComponent() {
const { user, isLoading, logout } = useAuth();
if (isLoading) return <p>Loading...</p>;
if (!user) return <p>Please sign in</p>;
return <button onClick={logout}>Sign Out</button>;
}What if you need to build something that doesn't fit the RPC model, like File Uploads, Stripe Webhooks, or WebSockets?
You can bypass the auto-generator and access the underlying Bun server directly using the rawFetch escape hatch in engine/src/app.ts.
Warning
Avoid Custom/Raw Endpoints for Standard Logic: It is highly unadvisable to use custom/raw endpoints (rawFetch) for regular API development. Bypassing the generator completely disables end-to-end type safety, automated OpenAPI documentation, and React Query wrappers. Always use the proper, function-first RPC model that this framework was made to be used with, reserving rawFetch strictly for special cases like multi-part file uploads or third-party webhooks.
// engine/src/app.ts
export function createApp() {
return createRuntime({
endpoints: [...endpoints],
// The escape hatch for custom logic
rawFetch: async (request) => {
const url = new URL(request.url);
if (request.method === "POST" && url.pathname === "/api/upload") {
// You have full access to standard Web APIs here!
const formData = await request.formData();
return new Response("Uploaded!", { status: 200 });
}
// Return undefined to let the auto-generated RPC router handle everything else
return undefined;
},
});
}- Keep
src/Clean: Never manually edit files insideengine/.generated/orweb/.generated/. They are overwritten on everymake generate. - Organization: any special logic for a route or api should be kept in same folder as the route or api itself, same with web, no global functions that are not even used other places, always keep it local.
- Strict Validation & Advanced Types: Your API functions should rely on standard TypeScript types for inputs. The generator will automatically convert them into internal schemas for runtime validation, protecting against invalid inputs (returning
400 Bad Request). We fully support highly complex types out of the box, including:- Nested Objects, Arrays, and
Record<string, unknown> - Unions (
|), Intersections (&), and Tuples - Dates and Literals
- Nested Objects, Arrays, and
- Use
useEngine: Always use the generateduseEnginehook instead of standardfetchon the frontend for instant Type-Safety and React Query caching.
_Built with coffee