MCPcopy Index your code
hub / github.com/Cododev-Technology/cpeak

github.com/Cododev-Technology/cpeak @v2.9.2

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.9.2 ↗ · + Follow
104 symbols 353 edges 32 files 0 documented · 0%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Cpeak

npm version

Cpeak is a minimal and fast Node.js framework inspired by Express.js & Fastify.

This project is designed to be improved until it's ready for use in complex production applications, aiming to be more performant and have a cleaner structure than Express.js and other common frameworks.

Cpeak replaces Express.js, body-parser, cookie-parser, compression, CORS, Passport and more, in one zero-dependency package. You can use it as a drop-in replacement for Express.js, and many npm packages that work with Express.js will also work with Cpeak.

Cpeak currently has almost all the features of Express.js, with roughly the same performance as Fastify. Additionally, it has a codebase that you can easily navigate, audit and change if you want. Benchmarks and test results, and videos on navigating and understanding the codebase will be added soon.

While Cpeak is being built for production, it is also an educational project that was started as part of the Understanding Node.js: Core Concepts course. If you want to learn how to build a framework like this, and get to a point where you can build things like this yourself and beyond, check out this course!

Why Cpeak?

  • Minimalism: No unnecessary bloat, with zero dependencies. Just the core essentials you need to build fast and reliable applications.
  • Performance: Engineered to be fast, Cpeak won’t sacrifice speed for excessive customizability.
  • Educational: Every new change made in the project will be explained in great detail in this YouTube playlist. Follow this project and let's see what it takes to build an industry-leading product!
  • Express.js Compatible: You can easily refactor from Cpeak to Express.js and vice versa. Many npm packages that work with Express.js will also work with Cpeak.

Table of Contents

Getting Started

Ready to dive in? Install Cpeak via npm:

npm install cpeak

Cpeak is a pure ESM package, and to use it, your project needs to be an ESM as well. You can learn more about that here.

Hello World App:

import cpeak from "cpeak";

const server = cpeak();

server.route("get", "/", (req, res) => {
  return res.json({ message: "Hi there!" });
});

server.listen(3000, () => {
  console.log("Server has started on port 3000");
});

Documentation

Including

Include the framework like this:

import cpeak from "cpeak";

Because of the minimalistic philosophy, you won’t add unnecessary objects to your memory as soon as you include the framework. If at any point you want to use a particular utility function (like parseJSON and serveStatic), include it like the line below, and only at that point will it be moved into memory:

import cpeak, { serveStatic, parseJSON } from "cpeak";

Initializing

Initialize the Cpeak server like this:

const server = cpeak();

Now you can use this server object to start listening, add route logic, add middleware functions, and handle errors.

Middleware

If you add a middleware function, that function will run before your route logic kicks in. Here you can customize the request object, return an error, or do anything else you want to do prior to your route logic, like authentication.

After calling next, the next middleware function is going to run if there’s any; otherwise, the route logic is going to run.

server.beforeEach((req, res, next) => {
  if (req.headers.authentication) {
    // Your authentication logic...
    req.userId = "<something>";
    req.custom = "This is some string";
    next();
  } else {
    // Return an error and close the request...
    return res.status(401).json({ error: "Unauthorized" });
  }
});

server.beforeEach((req, res, next) => {
  console.log(
    "The custom value was added from the previous middleware: ",
    req.custom
  );
  next();
});

Route Middleware

You can also add middleware functions for a particular route handler like this:

const requireAuth = (req, res, next) => {
  // Check if user is logged in, if so then:
  req.test = "this is a test value";
  next();

  // If user is not logged in:
  throw { status: 401, message: "Unauthorized" };
};

server.route("get", "/profile", requireAuth, (req, res) => {
  console.log(req.test); // this is a test value
});

You can add as many middleware functions as you want for a route:

server.route(
  "get",
  "/profile",
  requireAuth,
  anotherFunction,
  oneMore,
  (req, res) => {
    // your logic
  }
);

Route Handling

You can add new routes like this:

server.route("patch", "/the-path-you-want", (req, res) => {
  // your route logic
});

First add the HTTP method name you want to handle, then the path, and finally, the callback. The req and res object types are the same as in the Node.js HTTP module (http.IncomingMessage and http.ServerResponse). You can read more about them in the official Node.js documentation.

Under the hood, Cpeak stores your routes in a radix tree, so finding the right route for an incoming request is roughly O(log n) in your total route count. In plain terms, that means matching stays fast even when your app has hundreds or thousands of routes. You won't pay a linear scan per request as your route table grows.

Fallback Handler

If no route or middleware matches an incoming request, Cpeak returns a default 404 message. You can replace it with your own handler using server.fallback:

server.fallback((req, res) => {
  return res.status(404).json({ error: "not found" });
});

Use this for custom 404 pages, JSON error envelopes, or serving an SPA's index.html for unknown paths. Static, param, and * wildcard routes still win when they match, the fallback only fires once the router has no match.

URL Variables & Parameters

To be more consistent with the broader Node.js community and frameworks, we call the HTTP URL parameters (query strings) 'query', and the path variables (route parameters) 'params'.

Here’s how we can read both:

// Imagine request URL is example.com/test/my-title/more-text?filter=newest
server.route("patch", "/test/:title/more-text", (req, res) => {
  const title = req.params.title;
  const filter = req.query.filter;

  console.log(title); // my-title
  console.log(filter); // newest
});

Sending Files

You can send a file as a Node.js Stream anywhere in your route or middleware logic like this:

server.route("get", "/testing", (req, res) => {
  return res.status(200).sendFile("<file-path>", "<mime-type>");

  // Example:
  // return res.status(200).sendFile("./images/sun.jpeg", "image/jpeg");
});

The file’s binary content will be in the HTTP response body content. Make sure you specify a correct path relative to your CWD (use the path module for better compatibility).

The MIME type argument is optional. When omitted, Cpeak infers it from the file extension using its built-in MIME registry (see MIME Types):

return res.status(200).sendFile("./images/sun.jpeg");

Passing the MIME type explicitly is the fastest path, Cpeak skips the extension lookup entirely.

Redirecting

If you want to redirect to a new URL, you can simply do:

res.redirect("https://whatever.com");

MIME Types

serveStatic, res.sendFile, and res.render all share a single MIME type registry. Out of the box it covers the common web types:

  html: "text/html",
  css: "text/css",
  js: "application/javascript",
  jpg: "image/jpeg",
  jpeg: "image/jpeg",
  png: "image/png",
  svg: "image/svg+xml",
  gif: "image/gif",
  ico: "image/x-icon",
  txt: "text/plain",
  json: "application/json",
  webmanifest: "application/manifest+json",
  eot: "application/vnd.ms-fontobject",
  otf: "font/otf",
  ttf: "font/ttf",
  woff: "font/woff",
  woff2: "font/woff2"

If you need to serve something else, register it once on the cpeak() constructor:

const server = cpeak({
  mimeTypes: { mp3: "audio/mpeg", m4a: "audio/mp4" }
});

We keep this list small on purpose. Cpeak isn't going to load the thousands of MIME types from the IANA registry into your process memory on the off chance you might serve an .apk or a .fla one day. You tell us what you serve, we keep memory tight.

Compression

You can enable HTTP response compression at construction time. Once enabled, serveStatic, res.json() and res.sendFile() will compress eligible responses automatically, and you also get a res.compress() method on the response for custom payloads.

Fire it up with the defaults like this:

const server = cpeak({ compression: true });

Or pass options to tune the behavior:

const server = cpeak({
  compression: {
    threshold: 1024, // bytes — responses smaller than this are sent uncompressed. Default: 1024
    brotli: {},      // node:zlib BrotliOptions
    gzip: {},        // node:zlib ZlibOptions
    deflate: {}      // node:zlib ZlibOptions
  }
});

For arbitrary payloads, like a Buffer, string, or Readable stream, use res.compress:

server.route("get", "/report", async (req, res) => {
  const csv = await buildCsvReport();
  await res.compress("text/csv", csv);
});

When you're streaming, you can pass a known size as the third argument. Cpeak will use it to decide eligibility against threshold, and to set Content-Length if the body ends up being sent uncompressed:

import { Readable } from "node:stream";

server.route("get", "/proxy/feed", async (req, res) => {
  const upstream = await fetch("https://example.com/feed.xml");
  const size = Number(upstream.headers.get("content-length"));
  await res.compress("application/xml", Readable.fromWeb(upstream.body), size);
});

You must first enable compression at construction time to use res.compress.

Error Handling

If anywhere in your route functions or route middleware functions you want to return an error, you can just throw the error and let the automatic error handler catch it:

server.route("get", "/api/document/:title", (req, res) => {
  const title = req.params.title;

  if (title.length > 500) throw { status: 400, message: "Title too long." };

  // The rest of your logic...
});

Make sure to call server.handleErr and pass a function like this to have the automatic error handler work properly:

server.handleErr((error, req, res) => {
  if (error && error.status) {
    return res.status(error.status).json({ error: error.message });
  } else {
    // Log the unexpected errors somewhere so you can keep track of them...
    console.error(error);
    return res.status(500).json({
      error: "Sorry, something unexpected happened on our side."
    });
  }
});

The error object is the object that you threw earlier in your routes or middleware.

One thing to keep in mind: res.sendFile, res.render, res.compress, and res.json all return a Promise. Return that promise (or await it in an async handler) so the framework can route any rejection to your handleErr:

server.route("get", "/file", (req, res) => {
  return res.sendFile("./images/sun.jpeg", "image/jpeg");
});

Or, in an async handler that does other work alongside the send:

server.route("get", "/avatars/:id", async (req, res) => {
  const path = await db.lookupAvatarPath(req.params.id);
  await res.sendFile(path);
});

Listening

Start listening on a specific port like this:

server.listen(3000, () => {
  console.log("Server has started on port 3000");
});

server.listen accepts the same arguments as Node.js's http.Server.listen, so you can also pass a host, an options object, or a Unix socket path.

Util Functions

There are utility functions that you can include and use as middleware functions. These are meant to make it easier for you to build HTTP applications. In the future, many more will be added, and you only move them into memory once you include them. No need to have many npm dependencies for simple applications!

The list of utility functions as of now:

  • serveStatic
  • parseJSON
  • render
  • cookieParser
  • swagger
  • auth
  • cors

Including any one of them is done like this:

import cpeak, { utilName } from "cpeak";

serveStatic

With this middleware function, you can automatically set a folder in your project to b

Extension points exported contracts — how you extend this code

CpeakOptions (Interface)
(no doc)
lib/types.ts
PbkdfOptions (Interface)
(no doc)
lib/utils/types.ts
RadixNode (Interface)
(no doc)
lib/internal/router.ts
CpeakRequest (Interface)
(no doc)
lib/types.ts
AuthOptions (Interface)
(no doc)
lib/utils/types.ts
WildcardLeaf (Interface)
(no doc)
lib/internal/router.ts
CpeakResponse (Interface)
(no doc)
lib/types.ts
CookieOptions (Interface)
(no doc)
lib/utils/types.ts

Core symbols most depended-on inside this repo

route
called by 55
lib/index.ts
json
called by 54
lib/index.ts
status
called by 48
lib/index.ts
cpeak
called by 21
lib/index.ts
beforeEach
called by 20
lib/index.ts
listen
called by 20
lib/index.ts
close
called by 18
lib/index.ts
frameworkError
called by 18
lib/internal/errors.ts

Shape

Function 55
Method 26
Interface 12
Class 10
Enum 1

Languages

TypeScript100%

Modules by API surface

lib/index.ts27 symbols
lib/internal/router.ts12 symbols
lib/internal/compression.ts9 symbols
lib/utils/render.ts8 symbols
lib/utils/auth.ts8 symbols
lib/utils/cookieParser.ts6 symbols
lib/utils/types.ts4 symbols
lib/utils/parseJSON.ts4 symbols
lib/types.ts4 symbols
test/routeMiddleware.test.ts3 symbols
lib/utils/serveStatic.ts3 symbols
lib/utils/cors.ts3 symbols

For agents

$ claude mcp add cpeak \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact