Skip to content

Commit cd200d7

Browse files
updated readme and version
1 parent 3dde53a commit cd200d7

File tree

2 files changed

+87
-79
lines changed

2 files changed

+87
-79
lines changed

Readme.md

Lines changed: 86 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Benchmarked with `oha -c 100 -z 30s` on Windows 10:
2828
| Fastify | 15,519 | 16,434 |
2929
| Express | 13,138 | 13,458 |
3030

31-
> PrinceJS is **2.3× faster than Express**, matches Hono head-to-head, and sits at just **6.3kB gzipped** — loads in ~122ms on a slow 3G connection.
31+
> PrinceJS is **2.3× faster than Express**, matches Hono head-to-head, and sits at just **5.1kB gzipped** — loads in ~101ms on a slow 3G connection.
3232
3333
---
3434

@@ -61,11 +61,9 @@ app.listen(3000);
6161

6262
| Feature | Import |
6363
|---------|--------|
64-
| Routing, WebSockets, OpenAPI, Plugins, Lifecycle Hooks, Cookies, IP | `princejs` |
65-
| **Route Grouping** | `princejs` |
66-
| CORS, Logger, JWT, Auth, Rate Limit, Validate, Compress, Session, API Key | `princejs/middleware` |
67-
| **Secure Headers, Timeout, Request ID, IP Restriction, Static Files, JWKS** | `princejs/middleware` |
68-
| File Uploads, SSE, In-memory Cache, **Streaming** | `princejs/helpers` |
64+
| Routing, Route Grouping, WebSockets, OpenAPI, Plugins, Lifecycle Hooks, Cookies, IP | `princejs` |
65+
| CORS, Logger, JWT, JWKS, Auth, Rate Limit, Validate, Compress, Session, API Key, Secure Headers, Timeout, Request ID, IP Restriction, Static Files | `princejs/middleware` |
66+
| File Uploads, SSE, Streaming, In-memory Cache | `princejs/helpers` |
6967
| Cron Scheduler | `princejs/scheduler` |
7068
| JSX / SSR | `princejs/jsx` |
7169
| SQLite Database | `princejs/db` |
@@ -157,48 +155,56 @@ app.post("/admin", (req) => {
157155

158156
---
159157

160-
---
161158

162-
## 📁 Route Grouping
159+
## 🗂️ Route Grouping
163160

164-
Namespace routes under a shared prefix with optional shared middleware. Zero overhead at request time — just registers prefixed routes in the trie.
161+
Group routes under a shared prefix with optional shared middleware. Zero overhead at request time — purely a registration convenience.
165162

166163
```ts
164+
import { prince } from "princejs";
165+
166+
const app = prince();
167+
167168
// Basic grouping
168169
app.group("/api", (r) => {
169-
r.get("/users", () => ({ users: [] })); // → GET /api/users
170-
r.post("/users", (req) => req.parsedBody); // → POST /api/users
171-
r.get("/users/:id", (req) => ({ id: req.params?.id })); // → GET /api/users/:id
170+
r.get("/users", () => ({ users: [] }));
171+
r.post("/users", (req) => ({ created: req.parsedBody }));
172+
r.get("/users/:id", (req) => ({ id: req.params?.id }));
172173
});
174+
// → GET /api/users
175+
// → POST /api/users
176+
// → GET /api/users/:id
173177

174178
// With shared middleware — applies to every route in the group
175179
import { auth } from "princejs/middleware";
176180

177181
app.group("/admin", auth(), (r) => {
178-
r.get("/stats", () => ({ ok: true })); // → GET /admin/stats
179-
r.delete("/user", () => ({ deleted: true })); // → DELETE /admin/user
182+
r.get("/stats", () => ({ stats: {} }));
183+
r.delete("/users/:id", (req) => ({ deleted: req.params?.id }));
180184
});
181185

182186
// Chainable
183187
app
184188
.group("/v1", (r) => { r.get("/ping", () => ({ v: 1 })); })
185189
.group("/v2", (r) => { r.get("/ping", () => ({ v: 2 })); });
190+
191+
app.listen(3000);
186192
```
187193

188194
---
189195

190-
## 🔐 Security Middleware
196+
## 🛡️ Secure Headers
191197

192-
### Secure Headers
193-
194-
One call sets X-Frame-Options, HSTS, X-Content-Type-Options, X-XSS-Protection, and Referrer-Policy:
198+
One call sets all the security headers your production app needs:
195199

196200
```ts
197201
import { secureHeaders } from "princejs/middleware";
198202

199203
app.use(secureHeaders());
204+
// Sets: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection,
205+
// Strict-Transport-Security, Referrer-Policy
200206

201-
// Custom overrides
207+
// Custom options
202208
app.use(secureHeaders({
203209
xFrameOptions: "DENY",
204210
contentSecurityPolicy: "default-src 'self'",
@@ -207,18 +213,25 @@ app.use(secureHeaders({
207213
}));
208214
```
209215

210-
### Request Timeout
216+
---
217+
218+
## ⏱️ Request Timeout
211219

212220
Kill hanging requests before they pile up:
213221

214222
```ts
215223
import { timeout } from "princejs/middleware";
216224

217-
app.use(timeout(5000)); // 408 after 5s
218-
app.use(timeout(3000, "Gateway Timeout")); // custom message
225+
app.use(timeout(5000)); // 5 second global timeout → 408
226+
app.use(timeout(3000, "Slow!")); // custom message
227+
228+
// Per-route timeout
229+
app.get("/heavy", timeout(10000), (req) => heavyOperation());
219230
```
220231

221-
### Request ID
232+
---
233+
234+
## 🏷️ Request ID
222235

223236
Attach a unique ID to every request for distributed tracing and log correlation:
224237

@@ -228,96 +241,102 @@ import { requestId } from "princejs/middleware";
228241
app.use(requestId());
229242
// → sets req.id and X-Request-ID response header
230243

231-
// Custom header or generator
232-
app.use(requestId({
233-
header: "X-Trace-ID",
234-
generator: () => `req-${Date.now()}`,
235-
}));
244+
// Custom header name
245+
app.use(requestId({ header: "X-Trace-ID" }));
246+
247+
// Custom generator
248+
app.use(requestId({ generator: () => `req-${Date.now()}` }));
236249

237250
app.get("/", (req) => ({ requestId: req.id }));
238251
```
239252

240-
### IP Restriction
253+
---
254+
255+
## 🚫 IP Restriction
241256

242-
Allow or deny specific IPs:
257+
Allow or block specific IPs:
243258

244259
```ts
245260
import { ipRestriction } from "princejs/middleware";
246261

247262
// Only allow these IPs
248263
app.use(ipRestriction({ allowList: ["192.168.1.1", "10.0.0.1"] }));
249264

250-
// Block specific IPs
265+
// Block these IPs
251266
app.use(ipRestriction({ denyList: ["1.2.3.4"] }));
252267
```
253268

254-
### JWKS — Auth0, Clerk, Supabase
255-
256-
Verify JWTs against a remote JWKS endpoint — no symmetric key needed:
257-
258-
```ts
259-
import { jwks } from "princejs/middleware";
260-
261-
// Auth0
262-
app.use(jwks("https://YOUR_DOMAIN.auth0.com/.well-known/jwks.json"));
263-
264-
// Clerk
265-
app.use(jwks("https://YOUR_CLERK_DOMAIN/.well-known/jwks.json"));
266-
267-
// Keys are cached automatically — only fetched on rotation
268-
app.get("/protected", auth(), (req) => ({ user: req.user }));
269-
```
270-
271269
---
272270

273-
## 📂 Static Files
271+
## 📁 Static Files
274272

275273
Serve a directory of static files. Falls through to your routes if the file doesn't exist:
276274

277275
```ts
278276
import { serveStatic } from "princejs/middleware";
279277

280278
app.use(serveStatic("./public"));
281-
282-
// Your API routes still work normally
283-
app.get("/api/users", () => ({ users: [] }));
279+
// → GET /logo.png serves ./public/logo.png
280+
// → GET / serves ./public/index.html
281+
// → GET /api/users falls through to your route handler
284282
```
285283

286284
---
287285

288286
## 🌊 Streaming
289287

290-
Stream responses chunk by chunk — perfect for AI/LLM token output:
288+
Stream chunked responses for AI/LLM output, large payloads, or anything that generates data over time:
291289

292290
```ts
293291
import { stream } from "princejs/helpers";
294292

295-
// Async generator (cleanest for AI output)
293+
// Async generator cleanest for AI token streaming
296294
app.get("/ai", stream(async function*(req) {
297295
yield "Hello ";
296+
await delay(100);
298297
yield "from ";
299298
yield "PrinceJS!";
300299
}));
301300

302-
// Callback style
303-
app.get("/stream", stream((req) => {
301+
// Async callback
302+
app.get("/data", stream(async (req) => {
304303
req.streamSend("chunk 1");
304+
await fetchMoreData();
305305
req.streamSend("chunk 2");
306306
}));
307307

308-
// Async callback
309-
app.get("/slow-stream", stream(async (req) => {
310-
req.streamSend("Starting...");
311-
await fetch("https://api.openai.com/v1/chat/completions", { /* ... */ })
312-
.then(res => res.body?.pipeTo(new WritableStream({
313-
write(chunk) { req.streamSend(chunk); }
314-
})));
315-
}));
308+
// Custom content type for binary or JSON streams
309+
app.get("/events", stream(async function*(req) {
310+
for (const item of items) {
311+
yield JSON.stringify(item) + "\n";
312+
}
313+
}, { contentType: "application/x-ndjson" }));
314+
```
315+
316+
---
317+
318+
## 🔑 JWKS / Third-Party Auth
319+
320+
Verify JWTs from Auth0, Clerk, Supabase, or any JWKS endpoint — no symmetric key needed:
321+
322+
```ts
323+
import { jwks } from "princejs/middleware";
316324

317-
// Custom content type
318-
app.get("/binary", stream(() => { /* ... */ }, { contentType: "application/octet-stream" }));
325+
// Auth0
326+
app.use(jwks("https://your-domain.auth0.com/.well-known/jwks.json"));
327+
328+
// Clerk
329+
app.use(jwks("https://your-clerk-domain.clerk.accounts.dev/.well-known/jwks.json"));
330+
331+
// Supabase
332+
app.use(jwks("https://your-project.supabase.co/auth/v1/.well-known/jwks.json"));
333+
334+
// req.user is set after verification, same as jwt()
335+
app.get("/protected", auth(), (req) => ({ user: req.user }));
319336
```
320337

338+
---
339+
321340
## 📖 OpenAPI + Scalar Docs ✨
322341

323342
Auto-generate an OpenAPI 3.0 spec and serve a beautiful [Scalar](https://scalar.com) UI — all from a single `app.openapi()` call.
@@ -600,17 +619,6 @@ app.post(
600619
(req) => ({ created: req.parsedBody })
601620
);
602621

603-
// ── Route groups ─────────────────────────────────────────
604-
app.group("/v1", (r) => {
605-
r.get("/status", () => ({ version: 1, ok: true }));
606-
});
607-
608-
// ── Streaming ─────────────────────────────────────────────
609-
app.get("/ai", stream(async function*() {
610-
yield "Hello ";
611-
yield "World!";
612-
}));
613-
614622
// ── Cron ──────────────────────────────────────────────────
615623
cron("* * * * *", () => console.log("💓 heartbeat"));
616624

@@ -672,7 +680,7 @@ bun test
672680

673681
<div align="center">
674682

675-
**PrinceJS: 6.3kB. Hono-speed. Everything included. 👑**
683+
**PrinceJS: 5.1kB. Hono-speed. Everything included. 👑**
676684

677685
*Built with ❤️ in Nigeria*
678686

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "princejs",
3-
"version": "2.2.0",
3+
"version": "2.2.1",
44
"description": "An easy and fast backend framework that is among the top three — by a 13yo developer, for developers.",
55
"main": "dist/prince.js",
66
"types": "dist/prince.d.ts",

0 commit comments

Comments
 (0)