Cross-Platform Support
Lesan is designed to run seamlessly across Node.js, Bun, and Deno โ the three major JavaScript runtimes. This is achieved through a clean Platform Abstraction Layer (PAL) that isolates runtime-specific APIs behind consistent interfaces.
Supported Runtimesโ
| Runtime | Version | Status | Notes |
|---|---|---|---|
| Node.js | 18+ | โ Fully Supported | Production-ready |
| Bun | 1.0+ | โ Fully Supported | High performance |
| Deno | 1.40+ | โ Fully Supported | Native TypeScript |
Platform Abstraction Layerโ
Lesan's core framework is runtime-agnostic. All platform-specific functionality is abstracted behind interfaces:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Lesan Core Framework โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Platform Adapter (Auto-Detected) โ
โโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโค
โ Node โ Bun โ Deno โ Fallbackโ
โ Adapters โ Adapters โ Adapters โ (Node) โ
โโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโ
Adapter Interfacesโ
The platform layer provides adapters for:
| Adapter | Purpose | Key Methods |
|---|---|---|
| FileSystemAdapter | File I/O | readFile, writeFile, ensureDir |
| HttpServerAdapter | HTTP server | serve, serveFile, shutdown |
| EnvironmentAdapter | Environment vars | get, set, getAll |
| RuntimeAdapter | Runtime detection | detect, getVersion, getName |
| BundlerAdapter | Code bundling | bundle, transform |
Runtime Detectionโ
Lesan automatically detects the current runtime at startup:
import { detectRuntime, RuntimeType, isNode, isBun, isDeno } from "@hemedani/lesan";
const runtime = detectRuntime();
console.log(runtime.name); // "node", "bun", or "deno"
console.log(runtime.version); // "20.5.1", "1.0.0", etc.
if (isNode()) {
console.log("Running on Node.js");
}
if (isBun()) {
console.log("Running on Bun");
}
if (isDeno()) {
console.log("Running on Deno");
}
Node.jsโ
Installationโ
npm install @hemedani/lesan mongodb superstruct
Usageโ
import { lesan, MongoClient } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient("mongodb://localhost:27017/").connect();
coreApp.odm.setDb(client.db("myapp"));
await coreApp.runServer({ port: 8000 });
Node.js-Specific Featuresโ
The Node.js adapter uses:
node:httpfor HTTP server (createServer)node:fs/promisesfor file system operations- Web Standard
Request/Responseconverted from Node'sIncomingMessage/ServerResponse - Stream conversion via
Readable.toWeb()
Environment Variablesโ
import { env } from "@hemedani/lesan";
const port = env.get("PORT"); // Get string value
const debug = env.getBoolean("DEBUG"); // Parse as boolean
const maxConn = env.getNumber("MAX_CONN"); // Parse as number
File System Operationsโ
import { fs } from "@hemedani/lesan";
await fs.ensureDir("./uploads");
const content = await fs.readFile("./config.json");
await fs.writeFile("./output.txt", "Hello");
Bunโ
Installationโ
bun add @hemedani/lesan mongodb superstruct
Usageโ
import { lesan, MongoClient } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient("mongodb://localhost:27017/").connect();
coreApp.odm.setDb(client.db("myapp"));
await coreApp.runServer({ port: 8000 });
Bun-Specific Featuresโ
The Bun adapter leverages:
- Bun's native HTTP server (
Bun.serve()) - Bun's file system APIs (
Bun.file(),Bun.write()) - Native TypeScript support โ no transpilation needed
- Built-in bundler for playground assets
Performance Notesโ
Bun generally shows the best performance for:
- HTTP request throughput
- File system operations
- Startup time
# Run with Bun
bun run src/main.ts
# With hot reload
bun --watch run src/main.ts
Denoโ
Installationโ
Deno uses URL imports or an import map:
// Import directly from a URL (or use import map)
import { lesan, MongoClient } from "jsr:@hemedani/lesan";
Or with deno.json:
{
"imports": {
"@hemedani/lesan": "jsr:@hemedani/lesan"
}
}
Usageโ
import { lesan, MongoClient } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient("mongodb://localhost:27017/").connect();
coreApp.odm.setDb(client.db("myapp"));
await coreApp.runServer({ port: 8000 });
Deno-Specific Featuresโ
The Deno adapter uses:
- Deno's native HTTP server (
Deno.serve()) - Deno's file system APIs (
Deno.readFile(),Deno.writeFile()) - Permission-based security โ requires
--allow-net,--allow-read,--allow-write - Native TypeScript without build step
Running with Permissionsโ
deno run --allow-net --allow-read --allow-write --allow-env src/main.ts
Bundler Adapterโ
Deno's bundler uses esbuild via WASM for playground bundling:
import { bundler } from "@hemedani/lesan";
const result = await bundler.bundle({
entryPoints: ["./src/client.tsx"],
outdir: "./dist",
});
Platform Comparisonโ
| Feature | Node.js | Bun | Deno |
|---|---|---|---|
| Native TypeScript | โ (needs tsx/ts-node) | โ | โ |
| Package Manager | npm/yarn/pnpm | bun | deno (URL imports) |
| HTTP Performance | Good | Excellent | Good |
| MongoDB Driver | Official | Official | Official (npm compat) |
| Startup Time | ~500ms | ~50ms | ~200ms |
| File I/O | Callbacks/Promises | Native fast paths | Promises |
| Security Model | Application-level | Application-level | Permission flags |
| Built-in Bundler | โ | โ | โ (via deno_emit) |
| Hot Reload | nodemon/tsx | --watch | --watch |
Writing Runtime-Agnostic Codeโ
Lesan handles most runtime differences automatically. However, if you need runtime-specific logic:
Detecting the Runtimeโ
import { detectRuntime, RuntimeType } from "@hemedani/lesan";
const runtime = detectRuntime();
switch (runtime.type) {
case RuntimeType.Node:
// Node.js specific code
break;
case RuntimeType.Bun:
// Bun specific code
break;
case RuntimeType.Deno:
// Deno specific code
break;
}
Using Platform Adapters Directlyโ
import { fs, http, env, bundler } from "@hemedani/lesan";
// These work identically across all runtimes:
await fs.writeFile("./file.txt", "content");
await http.serve({ port: 3000 }, handler);
const apiKey = env.get("API_KEY");
MongoDB Compatibilityโ
Lesan uses the official MongoDB Node.js driver, which works on all three runtimes:
| Runtime | MongoDB Driver | Connection |
|---|---|---|
| Node.js | mongodb (npm) | Native |
| Bun | mongodb (npm) | Native (Bun has Node compat) |
| Deno | mongodb (npm via esm.sh) | Via npm compatibility layer |
Connection Examplesโ
Node.js / Bun:
import { MongoClient } from "mongodb"; // or from "@hemedani/lesan"
const client = await new MongoClient("mongodb://localhost:27017").connect();
Deno:
import { MongoClient } from "npm:mongodb@6"; // or via esm.sh
const client = await new MongoClient("mongodb://localhost:27017").connect();
Deploymentโ
Node.js Deploymentโ
Docker:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 8000
CMD ["node", "dist/main.js"]
PM2:
pm2 start dist/main.js --name lesan-api
Bun Deploymentโ
Docker:
FROM oven/bun:1
WORKDIR /app
COPY package.json ./
RUN bun install
COPY . .
EXPOSE 8000
CMD ["bun", "run", "src/main.ts"]
Direct:
bun run src/main.ts
Deno Deploymentโ
Docker:
FROM denoland/deno:1.40
WORKDIR /app
COPY deno.json main.ts ./
RUN deno cache main.ts
EXPOSE 8000
CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-write", "main.ts"]
Deno Deploy:
// main.ts
import { lesan } from "@hemedani/lesan";
const coreApp = lesan();
// ... setup ...
await coreApp.runServer({ port: 8000 });
Platform-Specific Configurationโ
Environment Variables by Runtimeโ
All runtimes support the same environment variable patterns through the env adapter:
// .env file (loaded automatically)
PORT=8000
MONGODB_URI=mongodb://localhost:27017/myapp
DEBUG=true
// Access anywhere
import { env } from "@hemedani/lesan";
const port = env.getNumber("PORT", 8000);
HTTP Server Optionsโ
All runtimes accept the same server options:
await coreApp.runServer({
port: 8000,
playground: true,
typeGeneration: true,
staticPath: ["./public"],
cors: ["https://myapp.com"],
});
File System Pathsโ
Use relative paths for cross-runtime compatibility:
// โ
Works on all runtimes
const filePath = "./uploads/image.jpg";
// โ Deno-specific
const filePath = "file:///uploads/image.jpg";
Troubleshootingโ
Node.js Issuesโ
Error: Cannot find module 'mongodb'
npm install mongodb superstruct
Error: ECONNREFUSED to MongoDB
- Ensure MongoDB is running:
mongodor Docker - Check connection string format
Bun Issuesโ
Error: mongodb driver compatibility
bun add mongodb
# Bun has built-in Node.js compatibility for most npm packages
Slow initial startup
- Bun caches dependencies after first run
- Use
bun installto warm the cache
Deno Issuesโ
Error: Permission denied
# Add required permissions
deno run --allow-net --allow-read --allow-write --allow-env main.ts
Error: Cannot resolve module
// Add to deno.json
{
"imports": {
"@hemedani/lesan": "jsr:@hemedani/lesan"
}
}
MongoDB driver on Deno
// Use npm: specifier for MongoDB driver
import { MongoClient } from "npm:mongodb@6";
Complete Runtime Examplesโ
Node.js Exampleโ
// src/main.ts
import { lesan, MongoClient, string, number, object } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient(process.env.MONGODB_URI!).connect();
coreApp.odm.setDb(client.db("app"));
const users = coreApp.odm.newModel("user", {
name: string(),
email: string(),
}, {});
coreApp.acts.setAct({
schema: "user",
actName: "getUser",
validator: object({ set: object({}), get: object() }),
fn: async (body) => users.findOne({ filters: {}, projection: body.details.get }),
});
await coreApp.runServer({ port: 8000 });
Run:
npx tsx src/main.ts
Bun Exampleโ
// src/main.ts
import { lesan, MongoClient, string, number, object } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient(Bun.env.MONGODB_URI!).connect();
coreApp.odm.setDb(client.db("app"));
// ... same as Node.js ...
await coreApp.runServer({ port: 8000 });
Run:
bun run src/main.ts
Deno Exampleโ
// main.ts
import { lesan, MongoClient, string, number, object } from "@hemedani/lesan";
const coreApp = lesan();
const client = await new MongoClient(Deno.env.get("MONGODB_URI")!).connect();
coreApp.odm.setDb(client.db("app"));
// ... same as Node.js ...
await coreApp.runServer({ port: 8000 });
Run:
deno run --allow-net --allow-read --allow-write --allow-env main.ts
API Reference Tableโ
Runtime Detectionโ
| Function | Description |
|---|---|
detectRuntime() | Detect current runtime |
isNode() | Check if running on Node.js |
isBun() | Check if running on Bun |
isDeno() | Check if running on Deno |
getRuntimeString() | Get runtime name string |
getRuntimeVersion() | Get runtime version |
meetsVersion(min) | Check version requirement |
Environment Adapterโ
| Method | Description |
|---|---|
env.get(key) | Get environment variable |
env.getString(key, default?) | Get as string |
env.getNumber(key, default?) | Get as number |
env.getBoolean(key, default?) | Get as boolean |
env.getArray(key, default?) | Get as array |
env.set(key, value) | Set environment variable |
env.getAll() | Get all variables |
File System Adapterโ
| Method | Description |
|---|---|
fs.readFile(path) | Read file contents |
fs.writeFile(path, data) | Write file |
fs.ensureDir(path) | Create directory if missing |
fs.exists(path) | Check if path exists |
fs.remove(path) | Remove file or directory |
HTTP Server Adapterโ
| Method | Description |
|---|---|
http.serve(options, handler) | Start HTTP server |
http.serveFile(request, path) | Serve static file |
http.getMimeType(path) | Get MIME type |
http.shutdown(options?) | Stop server |