princejs 1.9.4 โ†’ 1.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +316 -0
  2. package/package.json +1 -1
  3. package/Readme.md +0 -398
package/README.md ADDED
@@ -0,0 +1,316 @@
1
+ <div align="center">
2
+
3
+ <img src="./src/images/og.png" alt="PrinceJS"/>
4
+
5
+ # ๐Ÿ‘‘ PrinceJS
6
+
7
+ **Ultra-clean, modern & minimal Bun web framework.**
8
+ Built by a 13-year-old Nigerian developer. Among the top three in performance.
9
+
10
+ [![npm version](https://img.shields.io/npm/v/princejs?style=flat-square)](https://www.npmjs.com/package/princejs)
11
+ [![GitHub stars](https://img.shields.io/github/stars/MatthewTheCoder1218/princejs?style=flat-square)](https://github.com/MatthewTheCoder1218/princejs)
12
+ [![npm downloads](https://img.shields.io/npm/dt/princejs?style=flat-square)](https://www.npmjs.com/package/princejs)
13
+ [![license](https://img.shields.io/github/license/MatthewTheCoder1218/princejs?style=flat-square)](https://github.com/MatthewTheCoder1218/princejs/blob/main/LICENSE)
14
+
15
+ [**Website**](https://princejs.vercel.app) ยท [**npm**](https://www.npmjs.com/package/princejs) ยท [**GitHub**](https://github.com/MatthewTheCoder1218/princejs) ยท [**Twitter**](https://twitter.com/princejs_bun)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## โšก Performance
22
+
23
+ Benchmarked with `oha -c 100 -z 30s` on Windows 10:
24
+
25
+ | Framework | Req/s | Total |
26
+ |-----------|------:|------:|
27
+ | Elysia | 25,312 | 759k |
28
+ | Hono | 22,124 | 664k |
29
+ | **PrinceJS** | **21,748** | **653k** |
30
+ | Express | 9,325 | 280k |
31
+
32
+ > PrinceJS is **2.3ร— faster than Express** and sits comfortably in the top 3 โ€” at just **4.4kB gzipped**.
33
+
34
+ ---
35
+
36
+ ## ๐Ÿš€ Quick Start
37
+
38
+ ```bash
39
+ bun create princejs my-app
40
+ cd my-app
41
+ bun dev
42
+ ```
43
+
44
+ ```ts
45
+ import { prince } from "princejs";
46
+ import { cors, logger } from "princejs/middleware";
47
+
48
+ const app = prince();
49
+
50
+ app.use(cors());
51
+ app.use(logger());
52
+
53
+ app.get("/", () => ({ message: "Hello PrinceJS!" }));
54
+ app.get("/users/:id", (req) => ({ id: req.params.id }));
55
+
56
+ app.listen(3000);
57
+ ```
58
+
59
+ ---
60
+
61
+ ## ๐Ÿงฐ Features
62
+
63
+ | Feature | Import |
64
+ |---------|--------|
65
+ | Routing | `princejs` |
66
+ | Middleware (CORS, Logger, Rate Limit, Auth, JWT) | `princejs/middleware` |
67
+ | Zod Validation | `princejs/middleware` |
68
+ | File Uploads | `princejs/helpers` |
69
+ | WebSockets | `princejs` |
70
+ | Server-Sent Events | `princejs/helpers` |
71
+ | Sessions | `princejs/middleware` |
72
+ | Response Compression | `princejs/middleware` |
73
+ | In-memory Cache | `princejs/helpers` |
74
+ | Cron Scheduler | `princejs/scheduler` |
75
+ | **OpenAPI + Scalar Docs** | `princejs` |
76
+ | JSX / SSR | `princejs/jsx` |
77
+ | SQLite Database | `princejs/db` |
78
+ | Plugin System | `princejs` |
79
+ | End-to-End Type Safety | `princejs/client` |
80
+ | Deploy Adapters | `princejs/vercel` ยท `princejs/cloudflare` ยท `princejs/deno` |
81
+
82
+ ---
83
+
84
+ ## ๐Ÿ“– OpenAPI + Scalar Docs โœจ
85
+
86
+ Auto-generate an OpenAPI 3.0 spec and serve a beautiful [Scalar](https://scalar.com) UI โ€” all from a single `app.openapi()` call. Routes, validation, and docs stay in sync automatically.
87
+
88
+ ```ts
89
+ import { prince } from "princejs";
90
+ import { z } from "zod";
91
+
92
+ const app = prince();
93
+
94
+ const api = app.openapi({ title: "My API", version: "1.0.0" }, "/docs", { theme: "moon" });
95
+
96
+ api.route("GET", "/users/:id", {
97
+ summary: "Get user by ID",
98
+ tags: ["users"],
99
+ schema: {
100
+ response: z.object({ id: z.string(), name: z.string() }),
101
+ },
102
+ }, (req) => ({ id: req.params!.id, name: "Alice" }));
103
+
104
+ api.route("POST", "/users", {
105
+ summary: "Create user",
106
+ tags: ["users"],
107
+ schema: {
108
+ body: z.object({ name: z.string().min(2), email: z.string().email() }),
109
+ response: z.object({ id: z.string(), name: z.string(), email: z.string() }),
110
+ },
111
+ }, (req) => ({ id: crypto.randomUUID(), ...req.parsedBody }));
112
+
113
+ app.listen(3000);
114
+ // โ†’ GET /docs Scalar UI
115
+ // โ†’ GET /docs.json Raw OpenAPI JSON
116
+ ```
117
+
118
+ `api.route()` does three things at once:
119
+
120
+ - โœ… Registers the route on PrinceJS
121
+ - โœ… Auto-wires `validate(schema.body)` โ€” no separate import needed
122
+ - โœ… Writes the full OpenAPI spec entry
123
+
124
+ | `schema` key | Runtime | Scalar Docs |
125
+ |---|---|---|
126
+ | `body` | โœ… Validates request | โœ… requestBody model |
127
+ | `query` | โ€” | โœ… Typed query params |
128
+ | `response` | โ€” | โœ… 200 response model |
129
+
130
+ > Routes on `app.get()` / `app.post()` stay private โ€” never appear in docs.
131
+
132
+ **Themes:** `default` ยท `moon` ยท `purple` ยท `solarized` ยท `bluePlanet` ยท `deepSpace` ยท `saturn` ยท `kepler` ยท `mars`
133
+
134
+ ---
135
+
136
+ ## ๐Ÿ”Œ Plugin System
137
+
138
+ Share bundles of routes and middleware as reusable plugins:
139
+
140
+ ```ts
141
+ import { prince, type PrincePlugin } from "princejs";
142
+
143
+ const usersPlugin: PrincePlugin<{ prefix?: string }> = (app, opts) => {
144
+ const base = opts?.prefix ?? "";
145
+
146
+ app.use((req, next) => {
147
+ (req as any).fromPlugin = true;
148
+ return next();
149
+ });
150
+
151
+ app.get(`${base}/users`, (req) => ({
152
+ ok: true,
153
+ fromPlugin: (req as any).fromPlugin,
154
+ }));
155
+ };
156
+
157
+ const app = prince();
158
+ app.plugin(usersPlugin, { prefix: "/api" });
159
+ ```
160
+
161
+ ---
162
+
163
+ ## ๐Ÿ”’ End-to-End Type Safety
164
+
165
+ Define a contract once โ€” your client gets full TypeScript autocompletion automatically:
166
+
167
+ ```ts
168
+ type ApiContract = {
169
+ "GET /users/:id": {
170
+ params: { id: string };
171
+ response: { id: string; name: string };
172
+ };
173
+ "POST /users": {
174
+ body: { name: string };
175
+ response: { id: string; ok: boolean };
176
+ };
177
+ };
178
+
179
+ import { createClient } from "princejs/client";
180
+
181
+ const client = createClient<ApiContract>("http://localhost:3000");
182
+
183
+ const user = await client.get("/users/:id", { params: { id: "42" } });
184
+ console.log(user.name); // typed as string โœ…
185
+ ```
186
+
187
+ ---
188
+
189
+ ## ๐ŸŒ Deploy Adapters
190
+
191
+ **Vercel Edge** โ€” `api/[[...route]].ts`
192
+ ```ts
193
+ import { toVercel } from "princejs/vercel";
194
+ export default toVercel(app);
195
+ ```
196
+
197
+ **Cloudflare Workers** โ€” `src/index.ts`
198
+ ```ts
199
+ import { toWorkers } from "princejs/cloudflare";
200
+ export default toWorkers(app);
201
+ ```
202
+
203
+ **Deno Deploy** โ€” `main.ts`
204
+ ```ts
205
+ import { toDeno } from "princejs/deno";
206
+ Deno.serve(toDeno(app));
207
+ ```
208
+
209
+ ---
210
+
211
+ ## ๐ŸŽฏ Full Example
212
+
213
+ ```ts
214
+ import { prince } from "princejs";
215
+ import { cors, logger, rateLimit, auth, apiKey, jwt, session, compress, serve } from "princejs/middleware";
216
+ import { validate } from "princejs/validation";
217
+ import { cache, upload, sse } from "princejs/helpers";
218
+ import { cron } from "princejs/scheduler";
219
+ import { Html, Head, Body, H1, P, render } from "princejs/jsx";
220
+ import { db } from "princejs/db";
221
+ import { z } from "zod";
222
+
223
+ const app = prince(true);
224
+
225
+ // Global middleware
226
+ app.use(cors());
227
+ app.use(logger());
228
+ app.use(rateLimit({ max: 100, window: 60 }));
229
+ app.use(serve({ root: "./public" }));
230
+ app.use(jwt(key));
231
+ app.use(session({ secret: "key" }));
232
+ app.use(compress());
233
+
234
+ // JSX
235
+ const Page = () => Html(Head("Test Page"), Body(H1("Hello World"), P("This is a test")));
236
+ app.get("/jsx", () => render(Page()));
237
+
238
+ // Database
239
+ const users = db.sqlite("./db.sqlite", "CREATE TABLE users...");
240
+ app.get("/users", () => users.query("SELECT * FROM users"));
241
+
242
+ // WebSockets
243
+ app.ws("/chat", {
244
+ open: (ws) => ws.send("Welcome!"),
245
+ message: (ws, msg) => ws.send(`Echo: ${msg}`),
246
+ });
247
+
248
+ // Auth
249
+ app.get("/protected", auth(), (req) => ({ user: req.user }));
250
+ app.get("/api", apiKey({ keys: ["key_123"] }), handler);
251
+
252
+ // Helpers
253
+ app.get("/data", cache(60)(() => ({ time: Date.now() })));
254
+ app.post("/upload", upload(), (req) => ({ files: Object.keys(req.files || {}) }));
255
+ app.get("/events", sse(), (req) => {
256
+ setInterval(() => req.sseSend({ time: Date.now() }), 1000);
257
+ });
258
+
259
+ // Cron
260
+ cron("*/1 * * * *", () => console.log("PrinceJS heartbeat"));
261
+
262
+ // OpenAPI + Scalar docs
263
+ const api = app.openapi({ title: "PrinceJS App", version: "1.0.0" }, "/docs");
264
+ api.route("GET", "/items", {
265
+ summary: "List items",
266
+ tags: ["items"],
267
+ schema: {
268
+ query: z.object({ q: z.string().optional() }),
269
+ response: z.array(z.object({ id: z.string(), name: z.string() })),
270
+ },
271
+ }, () => [{ id: "1", name: "Widget" }]);
272
+
273
+ app.listen(3000);
274
+ ```
275
+
276
+ ---
277
+
278
+ ## ๐Ÿ“ฆ Installation
279
+
280
+ ```bash
281
+ bun add princejs
282
+ # or
283
+ npm install princejs
284
+ # or
285
+ yarn add princejs
286
+ ```
287
+
288
+ ---
289
+
290
+ ## ๐Ÿค Contributing
291
+
292
+ ```bash
293
+ git clone https://github.com/MatthewTheCoder1218/princejs
294
+ cd princejs
295
+ bun install
296
+ bun test
297
+ ```
298
+
299
+ ---
300
+
301
+ ## ๐Ÿ”— Links
302
+
303
+ - ๐ŸŒ Website: [princejs.vercel.app](https://princejs.vercel.app)
304
+ - ๐Ÿ“ฆ npm: [npmjs.com/package/princejs](https://www.npmjs.com/package/princejs)
305
+ - ๐Ÿ’ป GitHub: [github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
306
+ - ๐Ÿฆ Twitter: [@princejs_bun](https://twitter.com/princejs_bun)
307
+
308
+ ---
309
+
310
+ <div align="center">
311
+
312
+ **PrinceJS: Small in size. Giant in capability. ๐Ÿ‘‘**
313
+
314
+ *Built with โค๏ธ in Nigeria*
315
+
316
+ </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "princejs",
3
- "version": "1.9.4",
3
+ "version": "1.9.6",
4
4
  "description": "An easy and fast backend framework that is among the top three โ€” by a 13yo developer, for developers.",
5
5
  "main": "dist/prince.js",
6
6
  "types": "dist/prince.d.ts",
package/Readme.md DELETED
@@ -1,398 +0,0 @@
1
- # ๐Ÿ‘‘ **PrinceJS**
2
-
3
- ![PrinceJS Image](./src/images/og.png)
4
-
5
- ### โšก Ultra-clean, modern & minimal Bun web framework built by a 13 year old. Among the top three in performance.
6
-
7
- ![npm](https://img.shields.io/npm/v/princejs)
8
- ![stars](https://img.shields.io/github/stars/MatthewTheCoder1218/princejs)
9
- ![downloads](https://img.shields.io/npm/dt/princejs)
10
- ![license](https://img.shields.io/github/license/MatthewTheCoder1218/princejs)
11
-
12
- ---
13
-
14
- ## ๐Ÿš€ Quick Start
15
- ```bash
16
- bun create princejs my-app
17
- cd my-app
18
- bun dev
19
- ```
20
-
21
- ```ts
22
- import { prince } from "princejs";
23
- import { cors, logger } from "princejs/middleware";
24
-
25
- const app = prince();
26
-
27
- app.use(cors());
28
- app.use(logger());
29
-
30
- app.get("/", () => ({ message: "Hello PrinceJS!" }));
31
- app.get("/users/:id", (req) => ({ id: req.params.id }));
32
-
33
- app.listen(3000);
34
- ```
35
-
36
- ---
37
-
38
- ## ๐Ÿงฐ Features
39
-
40
- ```ts
41
- import { cors, logger, rateLimit, serve } from "princejs/middleware";
42
- import { validate } from "princejs/validation";
43
- import { z } from "zod";
44
-
45
- app
46
- .use(cors())
47
- .use(logger())
48
- .use(rateLimit({ max: 100, window: 60 }))
49
- .use(serve({ root: "./public" }))
50
- .use(validate(z.object({
51
- name: z.string(),
52
- age: z.number()
53
- })));
54
- ```
55
-
56
- ### Middleware
57
-
58
- * CORS
59
- * Logger
60
- * Rate Limiting
61
- * Static Files
62
-
63
- ### Validation (Zod)
64
-
65
- ### File Uploads
66
-
67
- ### Response Builder
68
-
69
- ### WebSocket Support
70
-
71
- ### Auth & API Keys
72
-
73
- ### Server-Sent Events
74
-
75
- ### Sessions
76
-
77
- ### Response Compression
78
-
79
- ### Route-level Middleware
80
-
81
- ### Plugin System
82
-
83
- You can share bundles of routes and middleware as plugins.
84
-
85
- ```ts
86
- import { prince, type PrincePlugin } from "princejs";
87
-
88
- const usersPlugin: PrincePlugin<{ prefix?: string }> = (app, opts) => {
89
- const base = opts?.prefix ?? "";
90
-
91
- // plugin-wide middleware
92
- app.use((req, next) => {
93
- (req as any).fromPlugin = true;
94
- return next();
95
- });
96
-
97
- // plugin routes
98
- app.get(`${base}/users`, (req) => ({
99
- ok: true,
100
- fromPlugin: (req as any).fromPlugin,
101
- }));
102
- };
103
-
104
- const app = prince();
105
- app.plugin(usersPlugin, { prefix: "/api" });
106
- ```
107
-
108
- ### OpenAPI + Scalar Docs
109
-
110
- Auto-generate an OpenAPI 3.0 spec and serve a beautiful [Scalar](https://scalar.com) API reference UI โ€” all from a single `app.openapi()` call. Routes, validation, and docs stay in sync automatically.
111
-
112
- ```ts
113
- import { prince } from "princejs";
114
- import { z } from "zod";
115
-
116
- const app = prince();
117
-
118
- const api = app.openapi({ title: "My API", version: "1.0.0" }, "/docs", { theme: "moon" });
119
-
120
- api.route("GET", "/users/:id", {
121
- summary: "Get user by ID",
122
- tags: ["users"],
123
- schema: {
124
- response: z.object({ id: z.string(), name: z.string() }),
125
- },
126
- }, (req) => ({ id: req.params!.id, name: "Alice" }));
127
-
128
- api.route("POST", "/users", {
129
- summary: "Create user",
130
- tags: ["users"],
131
- schema: {
132
- body: z.object({ name: z.string().min(2), email: z.string().email() }),
133
- response: z.object({ id: z.string(), name: z.string(), email: z.string() }),
134
- },
135
- }, (req) => ({ id: crypto.randomUUID(), ...req.parsedBody }));
136
-
137
- app.listen(3000);
138
- // โ†’ GET /docs Scalar UI
139
- // โ†’ GET /docs.json Raw OpenAPI JSON
140
- ```
141
-
142
- **`api.route()` does three things at once:**
143
- - Registers the route on PrinceJS (same as `app.get()` / `app.post()`)
144
- - Auto-wires `validate(schema.body)` middleware โ€” no separate import needed
145
- - Writes the full OpenAPI spec entry including path params, request body, query params, and response schema
146
-
147
- | `schema` key | Runtime effect | Scalar docs |
148
- |---|---|---|
149
- | `body` | โœ… Validates & strips via `validate()` | โœ… requestBody model |
150
- | `query` | โŒ docs only | โœ… typed query params |
151
- | `response` | โŒ docs only | โœ… 200 response model |
152
-
153
- Routes registered with `app.get()` / `app.post()` directly never appear in the docs โ€” useful for internal health checks, webhooks, and admin endpoints.
154
-
155
- **Available themes:** `default` ยท `moon` ยท `purple` ยท `solarized` ยท `bluePlanet` ยท `deepSpace` ยท `saturn` ยท `kepler` ยท `mars`
156
-
157
- ### Database (SQLite)
158
-
159
- ### End to End Type-Safety
160
-
161
- PrinceJS supports contract-based type safety to sync your frontend and backend seamlessly. By defining an API contract, your client receives full TypeScript autocompletion and type-checking for routes, parameters, and responses.
162
-
163
-
164
- **Define Your Contract**
165
-
166
- ```ts
167
- type ApiContract = {
168
- "GET /users/:id": {
169
- params: { id: string };
170
- response: { id: string; name: string };
171
- };
172
- "POST /users": {
173
- body: { name: string };
174
- response: { id: string; ok: boolean };
175
- };
176
- };
177
- ```
178
-
179
- **Initialize The Client**
180
-
181
- ```ts
182
- import { createClient } from "princejs/client";
183
-
184
- const client = createClient<ApiContract>("http://localhost:3000");
185
-
186
- // Fully typed request and response
187
- const user = await client.get("/users/:id", { params: { id: "42" } });
188
- console.log(user.name); // Typed as string
189
- ```
190
-
191
- ---
192
-
193
- ## Deploy (Vercel, Workers, Deno)
194
-
195
- Official adapters let you run the same Prince app on Vercel Edge, Cloudflare Workers, and Deno Deploy.
196
-
197
- **Vercel (Edge)** โ€” `api/[[...route]].ts`:
198
-
199
- ```ts
200
- import { prince } from "princejs";
201
- import { toVercel } from "princejs/vercel";
202
-
203
- const app = prince();
204
- app.get("/", () => ({ message: "Hello from Vercel!" }));
205
-
206
- export default toVercel(app);
207
- ```
208
-
209
- **Cloudflare Workers** โ€” `src/index.ts`:
210
-
211
- ```ts
212
- import { prince } from "princejs";
213
- import { toWorkers } from "princejs/cloudflare";
214
-
215
- const app = prince();
216
- app.get("/", () => ({ message: "Hello from Workers!" }));
217
-
218
- export default toWorkers(app);
219
- ```
220
-
221
- **Deno Deploy** โ€” `main.ts`:
222
-
223
- ```ts
224
- import { prince } from "princejs";
225
- import { toDeno } from "princejs/deno";
226
-
227
- const app = prince();
228
- app.get("/", () => ({ message: "Hello from Deno!" }));
229
-
230
- Deno.serve(toDeno(app));
231
- ```
232
-
233
- ---
234
-
235
- ## Performance With Oha (oha -c 100 -z 30s)
236
-
237
- | Framework | Req/s | Total |
238
- |-----------|----------------|--------|
239
- | Elysia | 25,312 req/s | 759k |
240
- | Hono | 22,124 req/s | 664k |
241
- | PrinceJS | 21,748 req/s | 653k |
242
- | Express | 9,325 req/s | 280k |
243
-
244
- ### Among the top three
245
-
246
- ---
247
-
248
- ## ๐ŸŽฏ Full Example
249
-
250
- ```ts
251
- import { prince } from "princejs";
252
- import { cors, logger, rateLimit, auth, apiKey, jwt, session, compress, serve } from "princejs/middleware";
253
- import { validate } from "princejs/validation";
254
- import { cache, upload, sse } from "princejs/helpers";
255
- import { cron, openapi } from "princejs/scheduler";
256
- import { Html, Head, Body, H1, P, render } from "princejs/jsx"
257
- import { db } from "princejs/db";
258
- import { z } from "zod";
259
-
260
- const app = prince(true);
261
-
262
- app.use(cors());
263
- app.use(logger());
264
- app.use(rateLimit({ max: 100, window: 60 }));
265
-
266
- app.use(serve({ root: "./public" }));
267
-
268
- app.use(validate(z.object({ name: z.string() })));
269
-
270
- app.use(jwt(key));
271
- app.use(session({ secret: "key" }));
272
- app.use(compress());
273
-
274
- const Page = () => Html(
275
- Head("Test Page"),
276
- Body(
277
- H1("Hello World"),
278
- P("This is a test")
279
- )
280
- );
281
-
282
- // With props (optional)
283
- const Card = (props: any) => Div(
284
- { className: "card", style: "padding: 1rem;" },
285
- H1(props.title),
286
- P(props.content)
287
- );
288
-
289
- // Without props
290
- const Simple = () => Div(
291
- H1("No Props Needed"),
292
- P("Just pure content")
293
- );
294
-
295
- const requireAuth = async (req: any, next: any) => {
296
- const token = req.headers.get("Authorization");
297
- if (!token) return new Response("Unauthorized", { status: 401 });
298
- req.user = { id: 1, name: "Alice" };
299
- return next();
300
- };
301
-
302
- app.get("/protected", requireAuth, async (req) => {
303
- return { user: req.user };
304
- });
305
-
306
- const users = db.sqlite("./db.sqlite", "CREATE TABLE users...");
307
-
308
- app.ws("/chat", {
309
- open: (ws) => ws.send("Welcome!"),
310
- message: (ws, msg) => ws.send(`Echo: ${msg}`)
311
- });
312
-
313
-
314
- app.get("/protected", auth(), (req) => ({ user: req.user }));
315
- app.get("/api", apiKey({ keys: ["key_123"] }), handler);
316
-
317
- app.get("/", () => ({ message: "Welcome to PrinceJS" }));
318
-
319
- app.get("/users/:id", (req) => ({ id: req.params.id }));
320
-
321
- app.get("/jsx", () => render(Page()));
322
-
323
- app.get("/data", cache(60)(() => ({ time: Date.now() })));
324
-
325
- app.post("/upload", upload(), (req) => ({ files: Object.keys(req.files || {}) }));
326
-
327
- app.get("/events", sse(), (req) => {
328
- setInterval(() => req.sseSend({ time: Date.now() }), 1000);
329
- });
330
-
331
- app.get("/count", (req) => ({ visits: req.session.visits++ || 1 }));
332
-
333
- app.get("/users", () => users.query("SELECT * FROM users"));
334
-
335
- cron("*/1 * * * *", () => console.log("PrinceJS heartbeat"));
336
-
337
- // OpenAPI + Scalar
338
- const api = app.openapi({ title: "PrinceJS App", version: "1.0.0" }, "/docs");
339
- api.route("GET", "/items", {
340
- summary: "List items",
341
- tags: ["items"],
342
- schema: {
343
- query: z.object({ q: z.string().optional() }),
344
- response: z.array(z.object({ id: z.string(), name: z.string() })),
345
- },
346
- }, () => [{ id: "1", name: "Widget" }]);
347
-
348
- app.listen(3000);
349
- ```
350
-
351
- ---
352
-
353
- ## ๐Ÿ“ฆ Installation
354
-
355
- ```bash
356
- npm install princejs
357
- # or
358
- bun add princejs
359
- # or
360
- yarn add princejs
361
- ```
362
-
363
- ---
364
-
365
- ## ๐Ÿ“š Documentation
366
-
367
- Visit: **princejs.vercel.app**
368
-
369
- ---
370
-
371
- ## ๐Ÿค Contributing
372
-
373
- ```bash
374
- git clone https://github.com/MatthewTheCoder1218/princejs
375
- cd princejs
376
- bun install
377
- bun test
378
- ```
379
-
380
- ---
381
-
382
- ## โญ Star This Repo
383
-
384
- If PrinceJS helped you, star the repo!
385
-
386
- GitHub: [https://github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
387
-
388
- ---
389
-
390
- ## ๐Ÿ”— Links
391
-
392
- * npm: [https://www.npmjs.com/package/princejs](https://www.npmjs.com/package/princejs)
393
- * GitHub: [https://github.com/MatthewTheCoder1218/princejs](https://github.com/MatthewTheCoder1218/princejs)
394
- * Twitter: [https://twitter.com/Lil_Prince_1218](https://twitter.com/Lil_Prince_1218)
395
-
396
- ---
397
-
398
- **PrinceJS: Small in size. Giant in capability. ๐Ÿš€**