npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hemedani/lesan

v0.2.3

Published

<div align="center"> <img src="./pages/src/img/besmelah.jpg" alt="بسم الله الرحمن الرحیم"> </div>

Readme

Why Lesan?

Lesan is a blazing-fast, cross-platform web framework and Object Document Mapper (ODM) designed to give you the exact data-fetching flexibility of GraphQL, without its heavy processing overhead, while maintaining the simplicity of REST.

Even though NoSQL is very fast, its complexities are very troublesome for large-scale projects. On the other hand, GraphQL shines in client-server connectivity but it has several weaknesses and is somewhat complex, adding another layer of complexity to the project. That’s why we created LESAN.

🚀 Now Cross-Platform! Lesan natively supports Node.js, Bun, and Deno with zero configuration. Write your code once and run it anywhere!

✨ What makes Lesan special?

  • 🎯 Client-Driven Projections: Similar to GraphQL, clients dictate exactly the shape and depth of the data they receive, including nested relations, but without the CPU cost of parsing a complex query language.
  • 🤝 One-Directional Magic, Bi-Directional Power: Relationships in Lesan are an absolute game-changer. You define a relationship from one direction (the model that needs it most), and Lesan automatically handles the immensely complex bi-directional embedding, syncing, array limits, sorting, and cascading updates/deletes behind the scenes. Goodbye to complex JOINs and manual NoSQL array updates!
  • 🛡️ End-to-End Type Safety: Run your server with the typeGeneration: true flag, and Lesan will auto-generate perfect client-side TypeScript definitions and a custom fetch wrapper. This guarantees flawless frontend integration and autocomplete.
  • Insane Performance: Stripped of unnecessary middleware bloat and built directly on the official MongoDB driver, Lesan's direct-to-database routing crushes traditional REST/ORM and GraphQL server speeds.
  • 🧩 Built for Microservices: The action-based architecture inherently supports breaking large monolithic systems down into isolated microservices effortlessly.

This video is an introductory tutorial on the Lesan framework in the Farsi language.

Benchmarks

We use this formula to calculate the difference : (B - A) ÷ A * 100
As you see on the chart:

  • Lesan return data to client 1168% faster than the prisma-express-rest. Which uses postgres as a database.
  • Lesan return data to client 1417% faster than the prisma-express-graphql. Which uses postgres as a database.
  • Lesan return data to client 4435% faster than the mongoose-express-rest (Note that we did not sort in this query)
  • Lesan return data to client 72289% faster than the mongo-express-rest (Note that we did not sort in this query)
  • Lesan return data to client 298971% faster than the mongoose-express-rest (used sortby)

Maybe we created the most performant framework in the world! see more detailed benchmark

Note: With our new cross-platform architecture, Lesan achieves over 10,000 requests per second on Bun and Deno! Check out our Cross-Platform Benchmarks.

Documentation

Installation

Lesan is designed to work seamlessly across all major JavaScript runtimes.

Node.js

npm install @hemedani/lesan mongodb

Bun

bun add @hemedani/lesan mongodb

Deno

import { lesan } from "jsr:@hemedani/lesan";
import { MongoClient } from "npm:mongodb";

A little trip

Look at the code below:

Create a file called main.ts (or main.js) and paste the code below into it:

import {
  ActFn,
  Document,
  Filter,
  lesan,
  number,
  object,
  ObjectId,
  optional,
  size,
  string,
} from "@hemedani/lesan"; // Use "jsr:@hemedani/lesan" for Deno
import { MongoClient } from "mongodb"; // Use "npm:mongodb" for Deno

const coreApp = lesan();

const client = await new MongoClient("mongodb://127.0.0.1:27017/").connect();
const db = client.db("civil");

coreApp.odm.setDb(db);

// ================== MODEL SECTION ==================
// ------------------ Country Model ------------------
const countryPure = {
  name: string(),
  population: number(),
  abb: string(),
};
const countryRelations = {};
const countries = coreApp.odm.newModel("country", countryPure, countryRelations);

// ------------------ User Model ------------------
const userPure = {
  name: string(),
  age: number(),
};
const users = coreApp.odm.newModel("user", userPure, {
  country: {
    optional: false,
    schemaName: "country",
    type: "single",
    relatedRelations: {
      users: {
        type: "multiple",
        limit: 50,
        sort: {
          field: "_id",
          order: "desc",
        },
      },
    },
  },
});

// ================== FUNCTIONS SECTION ==================
// ------------------ Add Country ------------------
const addCountryValidator = () => {
  return object({
    set: object(countryPure),
    get: coreApp.schemas.selectStruct("country", { users: 1 }),
  });
};

const addCountry: ActFn = async (body) => {
  const { name, population, abb } = body.details.set;
  return await countries.insertOne({
    doc: {
      name,
      population,
      abb,
    },
    projection: body.details.get,
  });
};

coreApp.acts.setAct({
  schema: "country",
  actName: "addCountry",
  validator: addCountryValidator(),
  fn: addCountry,
});

// ------------------ Get Countries  ------------------
const getCountriesValidator = () => {
  return object({
    set: object({
      page: number(),
      limit: number(),
    }),
    get: coreApp.schemas.selectStruct("country", 1),
  });
};

const getCountries: ActFn = async (body) => {
  let {
    set: { page, limit },
    get,
  } = body.details;

  page = page || 1;
  limit = limit || 50;
  const skip = limit * (page - 1);

  return await countries.find({ projection: get, filters: {} }).skip(skip).limit(limit).toArray();
};

coreApp.acts.setAct({
  schema: "country",
  actName: "getCountries",
  validator: getCountriesValidator(),
  fn: getCountries,
});

// --------------------- Add User ----------------------
const addUserValidator = () => {
  return object({
    set: object({
      ...userPure,
      country: string(),
    }),
    get: coreApp.schemas.selectStruct("user", 1),
  });
};
const addUser: ActFn = async (body) => {
  const { country, name, age } = body.details.set;

  return await users.insertOne({
    doc: { name, age },
    projection: body.details.get,
    relations: {
      country: {
        _ids: new ObjectId(country),
        relatedRelations: {
          users: true,
        },
      },
    },
  });
};

coreApp.acts.setAct({
  schema: "user",
  actName: "addUser",
  validator: addUserValidator(),
  fn: addUser,
});

// --------------------- Get Users ----------------------
const getUsersValidator = () => {
  return object({
    set: object({
      page: number(),
      take: number(),
      countryId: optional(size(string(), 24)),
    }),
    get: coreApp.schemas.selectStruct("user", { country: 1 }),
  });
};
const getUsers: ActFn = async (body) => {
  let {
    set: { page, limit, countryId },
    get,
  } = body.details;

  page = page || 1;
  limit = limit || 50;
  const skip = limit * (page - 1);
  const filters: Filter<Document> = {};
  countryId && (filters["country._id"] = new ObjectId(countryId));

  return await users.find({ projection: get, filters }).skip(skip).limit(limit).toArray();
};

coreApp.acts.setAct({
  schema: "user",
  actName: "getUsers",
  validator: getUsersValidator(),
  fn: getUsers,
});

// ================== RUN SECTION ==================
coreApp.runServer({ port: 1366, typeGeneration: false, playground: true });

Run the server

Depending on your runtime, run the following command in your terminal:

Node.js (requires tsx or similar for TypeScript):

npx tsx main.ts

Bun:

bun run main.ts

Deno:

deno run -A main.ts

You should see this message:

HTTP webserver running.
please send a post request to http://localhost:1366/lesan
you can visit playground on http://localhost:1366/playground

Listening on http://localhost:1366/

Now you can visit the playground at http://localhost:1366/playground and send requests to the server for addCountry, addUser, and getUsers.

Alternatively, you can send a POST request to http://localhost:1366/lesan with postman including the following in JSON format inside the body in order to retrieve the desired data:

{
  "service": "main",
  "model": "country",
  "act": "addCountry",
  "details": {
    "set": {
      "name": "Iran",
      "population": 85000000,
      "abb": "IR"
    },
    "get": {
      "_id": 1,
      "name": 1,
      "population": 1,
      "abb": 1
    }
  }
}

Screen Shot 1402-04-25 at 18 24 16

The Magic of Lesan Relationships ✨

In Lesan, relationships are One-Directional in definition, but fully embedded bi-directionally. When you link a User to a Country, Lesan seamlessly embeds the country details inside the user, and automatically embeds the user details inside the country's users array (even keeping the top 50 users sorted automatically!).

We handle all the heavy lifting of keeping this embedded data perfectly in sync across your entire database for blazing-fast reads. You can also control the exact level of penetration into the relationship depth. On the client-side, you simply describe what you want and get back exactly what you described—with zero backend refactoring!

Contributors

Many thanks to those who supported us