Skip to main content

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โ€‹

RuntimeVersionStatusNotes
Node.js18+โœ… Fully SupportedProduction-ready
Bun1.0+โœ… Fully SupportedHigh performance
Deno1.40+โœ… Fully SupportedNative 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:

AdapterPurposeKey Methods
FileSystemAdapterFile I/OreadFile, writeFile, ensureDir
HttpServerAdapterHTTP serverserve, serveFile, shutdown
EnvironmentAdapterEnvironment varsget, set, getAll
RuntimeAdapterRuntime detectiondetect, getVersion, getName
BundlerAdapterCode bundlingbundle, 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:http for HTTP server (createServer)
  • node:fs/promises for file system operations
  • Web Standard Request/Response converted from Node's IncomingMessage/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โ€‹

FeatureNode.jsBunDeno
Native TypeScriptโŒ (needs tsx/ts-node)โœ…โœ…
Package Managernpm/yarn/pnpmbundeno (URL imports)
HTTP PerformanceGoodExcellentGood
MongoDB DriverOfficialOfficialOfficial (npm compat)
Startup Time~500ms~50ms~200ms
File I/OCallbacks/PromisesNative fast pathsPromises
Security ModelApplication-levelApplication-levelPermission flags
Built-in BundlerโŒโœ…โœ… (via deno_emit)
Hot Reloadnodemon/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:

RuntimeMongoDB DriverConnection
Node.jsmongodb (npm)Native
Bunmongodb (npm)Native (Bun has Node compat)
Denomongodb (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: mongod or 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 install to 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โ€‹

FunctionDescription
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โ€‹

MethodDescription
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โ€‹

MethodDescription
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โ€‹

MethodDescription
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