@techiev2/vajra 1.0.0 → 1.0.1
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.
- package/README.md +193 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Vajra ⚡
|
|
2
|
+
|
|
3
|
+
 <!-- or use one of the above hosted URLs if you like -->
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
**Ultra-minimal, zero-dependency Node.js HTTP server**
|
|
7
|
+
Routing · Middleware · Multipart parsing · HTML templating
|
|
8
|
+
All in **111 lines** of pure JavaScript
|
|
9
|
+
|
|
10
|
+
## Name Origin
|
|
11
|
+
|
|
12
|
+
Vajra draws from the Rigvedic thunderbolt weapon of Indra — crafted from the bones of Sage Dadhichi, symbolizing unbreakable strength through selfless sacrifice.
|
|
13
|
+
|
|
14
|
+
Like the Vajra, this server delivers maximum power in minimal form.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
[](https://www.npmjs.com/package/vajra)
|
|
18
|
+
[](https://www.npmjs.com/package/vajra)
|
|
19
|
+
[](https://nodejs.org)
|
|
20
|
+
[](LICENSE)
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- Zero external dependencies
|
|
25
|
+
- Built-in routing with named parameters (`:id`)
|
|
26
|
+
- Global middleware support with `next()` chaining
|
|
27
|
+
- JSON, urlencoded, and **multipart/form-data** body parsing
|
|
28
|
+
- Fast HTML templating with loops, nested objects, and simple array headers
|
|
29
|
+
- Helper methods: `res.json()`, `res.html()`, `res.status()`, `res.writeMessage()`
|
|
30
|
+
- Payload size limiting with 413 responses
|
|
31
|
+
- Sensible defaults for 404/405/500
|
|
32
|
+
|
|
33
|
+
## Performance (Apple M4, Node 20+)
|
|
34
|
+
|
|
35
|
+
| Test Case | Vajra | Express + Multer | Notes |
|
|
36
|
+
|------------------------------------------------|----------------|------------------|---------------------------|
|
|
37
|
+
| 1MB Multipart Upload (wrk -t16 -c600) | **~94–98k req/s** | ~72k req/s | +30% faster |
|
|
38
|
+
| Idle RSS | ~52–53 MB | ~44 MB | Zero deps vs extra packages |
|
|
39
|
+
| Peak RSS under load | ~228 MB | ~209 MB | Full buffering trade-off |
|
|
40
|
+
| Code size (source) | **111 lines** | ~2k+ lines | Hand-crafted minimalism |
|
|
41
|
+
|
|
42
|
+
## Performance Benchmarks (wrk)
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install vajra
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
```JavaScript
|
|
55
|
+
import Vajra from '../index.js';
|
|
56
|
+
import { encode } from 'node:querystring';
|
|
57
|
+
|
|
58
|
+
async function getUsers(query = {}) {
|
|
59
|
+
return (await fetch(`https://jsonplaceholder.typicode.com/users?${encode(query)}`)).json()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const { get, post, use, start, setProperty } = Vajra.create();
|
|
63
|
+
|
|
64
|
+
setProperty({ viewsRoot: `${import.meta.url}/views` })
|
|
65
|
+
// Or as a key-value pair
|
|
66
|
+
// setProperty('viewsRoot', `${import.meta.url}/views`)
|
|
67
|
+
|
|
68
|
+
use((req, res, next) => {
|
|
69
|
+
console.log(`${req.method} ${req.url}`);
|
|
70
|
+
next();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
get('/', (req, res) => {
|
|
74
|
+
res.writeMessage('Hello from Vajra ⚡');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
post('/upload', (req, res) => {
|
|
78
|
+
res.json({ received: true, filesCount: req.files.length, files: req.files, body: req.body });
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
start({ port: 4002 }, () => {
|
|
82
|
+
console.log('Ready at http://localhost:4002');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
get('/api/users', async ({ query }, res) => {
|
|
86
|
+
const users = await getUsers(query)
|
|
87
|
+
return res.json({ users })
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
get('/web/users', async ({ query }, res) => {
|
|
91
|
+
const users = await getUsers(query)
|
|
92
|
+
const headers = Object.keys(users[0])
|
|
93
|
+
return res.html(`users.html`, { users, headers })
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## HTML Templating
|
|
98
|
+
```JavaScript
|
|
99
|
+
import Vajra from '../index.js';
|
|
100
|
+
const { get, post, use, start, setProperty } = Vajra.create();
|
|
101
|
+
|
|
102
|
+
get('/users', (req, res) => {
|
|
103
|
+
const data = {
|
|
104
|
+
users: [
|
|
105
|
+
{ id: 1, name: 'Alice' },
|
|
106
|
+
{ id: 2, name: 'Bob' }
|
|
107
|
+
],
|
|
108
|
+
headers: ['ID', 'Name']
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// If no view root is set, .html() expects the absolute path.
|
|
112
|
+
res.html('views/users.html', data);
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### views/users.html
|
|
117
|
+
```html
|
|
118
|
+
<table>
|
|
119
|
+
<thead>
|
|
120
|
+
{{# headers }}
|
|
121
|
+
<th>{{ header@ }}</th>
|
|
122
|
+
{{/ headers }}
|
|
123
|
+
</thead>
|
|
124
|
+
<tbody>
|
|
125
|
+
{{# users }}
|
|
126
|
+
<tr>
|
|
127
|
+
<td>{{ id }}</td>
|
|
128
|
+
<td>{{ name }}</td>
|
|
129
|
+
</tr>
|
|
130
|
+
{{/ users }}
|
|
131
|
+
</tbody>
|
|
132
|
+
</table>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Supports:
|
|
136
|
+
|
|
137
|
+
- Loops ({{# array }} ... {{/ array }})
|
|
138
|
+
- Dot notation ({{ user.name }})
|
|
139
|
+
- Special header shorthand ({{ header@ }} for simple arrays)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
## Configuration
|
|
143
|
+
```JavaScript
|
|
144
|
+
const app = vajra.create({
|
|
145
|
+
maxFileSize: 10 // in MB (default: 2)
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Set view root path
|
|
149
|
+
app.setProperty('viewRoot', './views');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## API
|
|
154
|
+
|
|
155
|
+
- `get/post/put/patch/delete/head/options(path, handler)`
|
|
156
|
+
- `use(middleware)`
|
|
157
|
+
- `start({ port, host }, callback?)`
|
|
158
|
+
- `setProperty(key, value)` or `setProperty({ key: value })`
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#### Response helpers:
|
|
162
|
+
|
|
163
|
+
`res.status(code)`
|
|
164
|
+
`res.json(data)`
|
|
165
|
+
`res.writeMessage(text)`
|
|
166
|
+
`res.html(pathOrString, data)`
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
## Philosophy
|
|
170
|
+
|
|
171
|
+
Vajra is built on the principle that minimalism can maximise outcomes.
|
|
172
|
+
|
|
173
|
+
Everything you need for real internal tools, admin panels, APIs, and prototypes — without the bloat.
|
|
174
|
+
|
|
175
|
+
No dependencies.
|
|
176
|
+
No build step.
|
|
177
|
+
Just copy `index.js` and go.
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
## Benchmarks & Memory
|
|
181
|
+
Run under extreme multipart load (wrk -t16 -c600 -d30s 1MB payloads):
|
|
182
|
+
|
|
183
|
+
Throughput: ~95k req/s
|
|
184
|
+
Idle RSS: ~52 MB
|
|
185
|
+
Peak under load: ~228 MB (drops back on idle)
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
MIT
|
|
189
|
+
|
|
190
|
+
## Credits
|
|
191
|
+
Hand-crafted by [[Sriram Velamur](https://linkedin.com/in/techiev2)/[@techiev2](https://x.com/techiev2)]
|
|
192
|
+
|
|
193
|
+
Inspired by the desire for a truly tiny, powerful, and dependency-free Node server.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@techiev2/vajra",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Blazing-fast, zero-dependency Node.js server with routing, middleware, multipart uploads, and templating. 111 lines · ~95k req/s · ~52 MB idle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"http-server",
|