edgewiz
v1.1.1
Published
Lightweight multi-runtime middleware for rate limiting, request coalescing, and CORS.
Maintainers
Readme
EdgeWiz
A lightweight middleware library for building web servers across multiple JavaScript runtimes.
Write middleware once and run it on:
- Node.js
- Bun
- Deno
- Cloudflare Workers
- AWS Lambda
Installation
npm install edgewizFeatures
- 🌍 Cross-runtime middleware
- 🚀 Rate limiting
- 🔒 CORS
- ⚡ Request coalescing
- 🔧 Middleware composition
- 📝 TypeScript support
- 📦 ESM & CommonJS
Quick Start
Node.js (Express)
import express from "express";
import { toNodeMiddleware, rateLimit } from "edgewiz";
const app = express();
app.use(
toNodeMiddleware(
rateLimit({
limit: 100,
windowMs: 15 * 60 * 1000,
})
)
);
app.get("/", (_, res) => {
res.json({ message: "Hello World" });
});
app.listen(3000);Bun / Deno / Cloudflare Workers
import { cors, toFetchHandler } from "edgewiz";
const middleware = cors({
origin: "*",
});
const handler = toFetchHandler(
middleware,
async () => new Response("Hello World")
);
export default {
fetch: handler,
};AWS Lambda
import { rateLimit, toLambdaHandler } from "edgewiz";
export const handler = toLambdaHandler(
rateLimit({
limit: 50,
windowMs: 60 * 1000,
}),
async () => ({
statusCode: 200,
headers: {
"content-type": "application/json",
},
body: JSON.stringify({
message: "OK",
}),
})
);Middleware
Rate Limiting
import { rateLimit } from "edgewiz";
const middleware = rateLimit({
limit: 100,
windowMs: 15 * 60 * 1000,
});Options
| Option | Description |
|---------|-------------|
| limit | Maximum requests per window |
| max | Alias for limit (Express compatibility) |
| windowMs | Time window in milliseconds |
| keyGenerator | Generate a custom rate-limit key |
| store | Custom storage implementation |
| standardHeaders | Adds RateLimit-* headers |
| legacyHeaders | Adds X-RateLimit-* headers |
Built-in Key Generators
import {
rateLimit,
ipKeyGenerator,
userIdKeyGenerator,
ipPathKeyGenerator,
apiKeyGenerator,
} from "edgewiz";
const middleware = rateLimit({
limit: 100,
windowMs: 60 * 1000,
keyGenerator: ipKeyGenerator,
});Available generators:
ipKeyGeneratoruserIdKeyGeneratoripPathKeyGeneratorapiKeyGenerator
CORS
import { cors } from "edgewiz";
const middleware = cors({
origin: "*",
methods: ["GET", "POST"],
allowedHeaders: [
"content-type",
"authorization",
],
credentials: true,
maxAge: 86400,
});Origin Examples
Allow all origins
cors({
origin: "*",
});Allow a single origin
cors({
origin: "https://example.com",
});Allow multiple origins
cors({
origin: [
"https://example.com",
"https://app.example.com",
],
});Custom validation
cors({
origin(origin) {
return origin?.endsWith(".example.com");
},
});Request Coalescing
import { coalesce } from "edgewiz";
const middleware = coalesce({
keyGenerator: (req) => `${req.method}:${req.url}`,
});Multiple identical concurrent requests are processed only once. Remaining requests receive the same response.
Composing Middleware
import {
compose,
rateLimit,
cors,
coalesce,
} from "edgewiz";
const middleware = compose(
rateLimit({
limit: 100,
windowMs: 60 * 1000,
}),
cors({
origin: "*",
}),
coalesce()
);Middleware executes from top to bottom.
Custom Middleware
import type {
CoreMiddleware,
} from "edgewiz";
const logger: CoreMiddleware = async (
req,
next
) => {
console.log(req.method, req.url);
const response = await next();
response.headers["x-powered-by"] = "EdgeWiz";
return response;
};Adapters
Node.js
import { toNodeMiddleware } from "edgewiz/adapters/node";Extracts
- IP
- Method
- URL
- Headers
Fetch API
import { toFetchHandler } from "edgewiz/adapters/fetch";Supports
- Bun
- Deno
- Cloudflare Workers
AWS Lambda
import { toLambdaHandler } from "edgewiz/adapters/lambda";Extracts
- IP
- Method
- Path
- Headers
Types
NormalizedRequest
interface NormalizedRequest {
method: string;
url: string;
headers: Record<
string,
string | string[]
>;
ip?: string;
body?: string;
}NormalizedResponse
interface NormalizedResponse {
status: number;
headers: Record<
string,
string | string[]
>;
body?: string | null;
}CoreMiddleware
type CoreMiddleware = (
req: NormalizedRequest,
next: () => Promise<NormalizedResponse>
) => Promise<NormalizedResponse>;Utilities
import {
getHeader,
setHeader,
} from "edgewiz";
const contentType = getHeader(
req.headers,
"content-type"
);
setHeader(
res.headers,
"cache-control",
"no-cache"
);Project Structure
src/
├── index.ts
├── types.ts
├── adapters/
│ ├── node.ts
│ ├── fetch.ts
│ └── lambda.ts
├── rate-limit/
├── cors/
└── coalesce/
test/
dist/Development
Build
npm run buildTest
npm run testWatch
npm run devNotes
- Use a distributed store (Redis, etc.) for production rate limiting.
- Request coalescing only deduplicates concurrent requests.
- When using CORS with
credentials: true, do not useorigin: "*". - Lambda in-memory state is container-specific.
License
MIT
