@flight-framework/http 0.0.2 → 0.0.4

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 (2) hide show
  1. package/README.md +485 -61
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,40 @@
1
1
  # @flight-framework/http
2
2
 
3
- Ultra-fast HTTP server for Flight Framework, built on Web Standards.
3
+ HTTP server for Flight Framework. Built on Web Standard APIs with radix-tree routing for maximum performance. Runs on Node.js, Bun, and Deno.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [Installation](#installation)
9
+ - [Quick Start](#quick-start)
10
+ - [Routing](#routing)
11
+ - [Route Parameters](#route-parameters)
12
+ - [Middleware](#middleware)
13
+ - [Context API](#context-api)
14
+ - [Request Handling](#request-handling)
15
+ - [Response Helpers](#response-helpers)
16
+ - [Error Handling](#error-handling)
17
+ - [Sub-Routers](#sub-routers)
18
+ - [Runtime Adapters](#runtime-adapters)
19
+ - [Static Files](#static-files)
20
+ - [CORS](#cors)
21
+ - [API Reference](#api-reference)
22
+ - [License](#license)
23
+
24
+ ---
25
+
26
+ ## Features
27
+
28
+ - Radix-tree routing for fast path matching
29
+ - Native Request/Response APIs (Web Standard)
30
+ - Multi-runtime support: Node.js, Bun, Deno
31
+ - Middleware with async/await
32
+ - Type-safe route parameters
33
+ - Built-in helpers for JSON, HTML, redirects
34
+ - Zero external runtime dependencies
35
+ - Full TypeScript support
36
+
37
+ ---
4
38
 
5
39
  ## Installation
6
40
 
@@ -8,6 +42,8 @@ Ultra-fast HTTP server for Flight Framework, built on Web Standards.
8
42
  npm install @flight-framework/http
9
43
  ```
10
44
 
45
+ ---
46
+
11
47
  ## Quick Start
12
48
 
13
49
  ```typescript
@@ -16,140 +52,528 @@ import { serve } from '@flight-framework/http/node';
16
52
 
17
53
  const app = createServer();
18
54
 
19
- // Simple JSON response
20
55
  app.get('/', (c) => c.json({ message: 'Hello Flight!' }));
21
56
 
22
- // Route params
23
57
  app.get('/users/:id', (c) => {
24
58
  return c.json({ userId: c.params.id });
25
59
  });
26
60
 
27
- // POST with body
28
61
  app.post('/users', async (c) => {
29
62
  const body = await c.req.json();
30
- return c.json({ created: true, data: body }, 201);
63
+ return c.json({ created: true, user: body }, 201);
31
64
  });
32
65
 
33
- // Start server
34
66
  serve(app, { port: 3000 });
67
+ console.log('Server running at http://localhost:3000');
35
68
  ```
36
69
 
37
- ## Features
70
+ ---
38
71
 
39
- - **Ultra-fast** - Radix-tree based routing for maximum performance
40
- - **Web Standards** - Uses native Request/Response APIs
41
- - **Multi-runtime** - Works with Node.js, Bun, and Deno
42
- - **Lightweight** - Minimal dependencies (~3kb core)
43
- - **TypeScript** - Full type safety out of the box
72
+ ## Routing
44
73
 
45
- ## Runtime Adapters
74
+ Register routes using HTTP method helpers:
46
75
 
47
- ### Node.js
76
+ ```typescript
77
+ app.get('/path', handler); // GET
78
+ app.post('/path', handler); // POST
79
+ app.put('/path', handler); // PUT
80
+ app.patch('/path', handler); // PATCH
81
+ app.delete('/path', handler); // DELETE
82
+ app.options('/path', handler); // OPTIONS
83
+ app.head('/path', handler); // HEAD
84
+
85
+ // All methods
86
+ app.all('/path', handler);
87
+
88
+ // Multiple methods
89
+ app.on(['GET', 'POST'], '/path', handler);
90
+ ```
91
+
92
+ ### Route Patterns
48
93
 
49
94
  ```typescript
50
- import { createServer } from '@flight-framework/http';
51
- import { serve } from '@flight-framework/http/node';
95
+ // Static path
96
+ app.get('/about', handler);
52
97
 
53
- serve(app, { port: 3000 });
98
+ // Single parameter
99
+ app.get('/users/:id', handler);
100
+
101
+ // Multiple parameters
102
+ app.get('/posts/:year/:month/:slug', handler);
103
+
104
+ // Optional parameter
105
+ app.get('/files/:path?', handler);
106
+
107
+ // Wildcard (catch-all)
108
+ app.get('/assets/*', handler);
109
+
110
+ // Named wildcard
111
+ app.get('/docs/:path*', handler);
54
112
  ```
55
113
 
56
- ### Bun
114
+ ---
115
+
116
+ ## Route Parameters
117
+
118
+ Access route parameters from the context:
57
119
 
58
120
  ```typescript
59
- import { createServer } from '@flight-framework/http';
60
- import { serve } from '@flight-framework/http/bun';
121
+ // Route: /users/:id/posts/:postId
122
+ app.get('/users/:id/posts/:postId', (c) => {
123
+ const { id, postId } = c.params;
124
+ return c.json({ userId: id, postId });
125
+ });
61
126
 
62
- serve(app, { port: 3000 });
127
+ // Wildcard parameters
128
+ // Route: /files/*
129
+ // Request: /files/images/photo.jpg
130
+ app.get('/files/*', (c) => {
131
+ const path = c.params['*']; // "images/photo.jpg"
132
+ return c.text(`File: ${path}`);
133
+ });
63
134
  ```
64
135
 
65
- ### Deno
136
+ ### Type-Safe Parameters
66
137
 
67
138
  ```typescript
68
- import { createServer } from '@flight-framework/http';
69
- import { serve } from '@flight-framework/http/deno';
139
+ import type { Context } from '@flight-framework/http';
70
140
 
71
- serve(app, { port: 3000 });
141
+ interface UserParams {
142
+ id: string;
143
+ postId: string;
144
+ }
145
+
146
+ app.get('/users/:id/posts/:postId', (c: Context<UserParams>) => {
147
+ c.params.id; // string (typed)
148
+ c.params.postId; // string (typed)
149
+ });
72
150
  ```
73
151
 
152
+ ---
153
+
74
154
  ## Middleware
75
155
 
156
+ Middleware functions run before route handlers:
157
+
76
158
  ```typescript
77
- // Logging middleware
159
+ // Global middleware (runs on all routes)
78
160
  app.use(async (c, next) => {
79
161
  const start = performance.now();
80
162
  const response = await next();
81
163
  const duration = performance.now() - start;
82
- console.log(`${c.req.method} ${c.req.url} - ${duration}ms`);
164
+ console.log(`${c.req.method} ${c.req.url} - ${duration.toFixed(2)}ms`);
83
165
  return response;
84
166
  });
85
167
 
86
- // Auth middleware
87
- app.use(async (c, next) => {
88
- const token = c.header('Authorization');
168
+ // Path-specific middleware
169
+ app.use('/api/*', async (c, next) => {
170
+ // Only runs on /api/* routes
171
+ return next();
172
+ });
173
+ ```
174
+
175
+ ### Authentication Middleware
176
+
177
+ ```typescript
178
+ const authMiddleware = async (c, next) => {
179
+ const token = c.header('Authorization')?.replace('Bearer ', '');
180
+
89
181
  if (!token) {
90
182
  return c.json({ error: 'Unauthorized' }, 401);
91
183
  }
92
- c.set('user', { id: '123' });
184
+
185
+ const user = await verifyToken(token);
186
+ if (!user) {
187
+ return c.json({ error: 'Invalid token' }, 401);
188
+ }
189
+
190
+ // Store user in context for later use
191
+ c.set('user', user);
93
192
  return next();
193
+ };
194
+
195
+ // Apply to specific routes
196
+ app.use('/api/*', authMiddleware);
197
+
198
+ // Access in route handler
199
+ app.get('/api/profile', (c) => {
200
+ const user = c.get('user');
201
+ return c.json(user);
94
202
  });
95
203
  ```
96
204
 
97
- ## Context Helpers
205
+ ### Middleware Chain
206
+
207
+ Multiple middleware functions run in order:
208
+
209
+ ```typescript
210
+ app.get('/protected',
211
+ authMiddleware,
212
+ rateLimitMiddleware,
213
+ validationMiddleware,
214
+ (c) => {
215
+ return c.json({ data: 'secret' });
216
+ }
217
+ );
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Context API
223
+
224
+ The context object provides access to request data and response helpers:
98
225
 
99
226
  ```typescript
100
227
  app.get('/demo', (c) => {
101
- // JSON response
102
- return c.json({ data: 'value' });
228
+ // Request object (Web Standard)
229
+ c.req; // Request
230
+ c.req.method; // "GET"
231
+ c.req.url; // Full URL
103
232
 
104
- // Text response
105
- return c.text('Hello');
233
+ // Route parameters
234
+ c.params; // { id: "123" }
235
+ c.params.id; // "123"
106
236
 
107
- // HTML response
108
- return c.html('<h1>Hello</h1>');
237
+ // Query parameters
238
+ c.query('page'); // "1" or undefined
239
+ c.query('page', '1'); // "1" (with default)
240
+ c.queries('tags'); // ["a", "b"] (array)
109
241
 
110
- // Redirect
111
- return c.redirect('/other');
242
+ // Headers
243
+ c.header('Content-Type'); // "application/json"
244
+ c.header('X-Custom'); // Custom header value
112
245
 
113
- // Access headers
114
- const auth = c.header('Authorization');
246
+ // Cookies
247
+ c.cookie('session'); // Cookie value
115
248
 
116
- // Access cookies
117
- const session = c.cookie('session');
249
+ // Context storage
250
+ c.set('key', 'value'); // Store value
251
+ c.get('key'); // Retrieve value
118
252
 
119
- // Access params
120
- const id = c.params.id;
253
+ return c.json({ ok: true });
121
254
  });
122
255
  ```
123
256
 
124
- ## API Reference
257
+ ---
125
258
 
126
- ### `createServer(options?)`
259
+ ## Request Handling
127
260
 
128
- Create a new Flight HTTP server.
261
+ ### JSON Body
129
262
 
130
- ### `app.get/post/put/delete/patch(path, ...handlers)`
263
+ ```typescript
264
+ app.post('/api/users', async (c) => {
265
+ const body = await c.req.json();
266
+ // body is parsed JSON
267
+ return c.json({ received: body });
268
+ });
269
+ ```
131
270
 
132
- Register a route handler.
271
+ ### Form Data
133
272
 
134
- ### `app.use(...middleware)`
273
+ ```typescript
274
+ app.post('/upload', async (c) => {
275
+ const form = await c.req.formData();
276
+ const name = form.get('name');
277
+ const file = form.get('file'); // File object
278
+
279
+ return c.json({ name, fileName: file?.name });
280
+ });
281
+ ```
135
282
 
136
- Add global middleware.
283
+ ### Raw Text
137
284
 
138
- ### `app.route(path, subRouter)`
285
+ ```typescript
286
+ app.post('/webhook', async (c) => {
287
+ const text = await c.req.text();
288
+ return c.text(`Received: ${text}`);
289
+ });
290
+ ```
139
291
 
140
- Mount a sub-router.
292
+ ### Raw Binary
141
293
 
142
- ### `app.notFound(handler)`
294
+ ```typescript
295
+ app.post('/binary', async (c) => {
296
+ const buffer = await c.req.arrayBuffer();
297
+ return c.json({ bytes: buffer.byteLength });
298
+ });
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Response Helpers
304
+
305
+ ```typescript
306
+ // JSON response
307
+ c.json({ data: 'value' });
308
+ c.json({ created: true }, 201);
309
+ c.json({ error: 'Not found' }, 404);
310
+
311
+ // Text response
312
+ c.text('Hello, World!');
313
+ c.text('Created', 201);
314
+
315
+ // HTML response
316
+ c.html('<h1>Hello</h1>');
317
+ c.html('<!DOCTYPE html>...', 200);
318
+
319
+ // Redirect
320
+ c.redirect('/new-location');
321
+ c.redirect('/login', 302); // Temporary (default)
322
+ c.redirect('/moved', 301); // Permanent
323
+
324
+ // No Content
325
+ c.body(null, 204);
326
+
327
+ // Custom response
328
+ return new Response(body, {
329
+ status: 200,
330
+ headers: { 'X-Custom': 'value' },
331
+ });
332
+
333
+ // Set response headers
334
+ c.header('X-Request-Id', requestId);
335
+ c.header('Cache-Control', 'max-age=3600');
336
+
337
+ // Set cookies
338
+ c.cookie('session', token, {
339
+ httpOnly: true,
340
+ secure: true,
341
+ sameSite: 'Strict',
342
+ maxAge: 60 * 60 * 24, // 1 day
343
+ });
344
+ ```
143
345
 
144
- Set custom 404 handler.
346
+ ---
145
347
 
146
- ### `app.onError(handler)`
348
+ ## Error Handling
147
349
 
148
- Set custom error handler.
350
+ ### Global Error Handler
149
351
 
150
- ### `app.fetch(request)`
352
+ ```typescript
353
+ app.onError((error, c) => {
354
+ console.error('Error:', error);
355
+
356
+ if (error instanceof ValidationError) {
357
+ return c.json({ error: error.message }, 400);
358
+ }
359
+
360
+ return c.json({ error: 'Internal Server Error' }, 500);
361
+ });
362
+ ```
363
+
364
+ ### 404 Not Found
365
+
366
+ ```typescript
367
+ app.notFound((c) => {
368
+ return c.json({
369
+ error: 'Not Found',
370
+ path: new URL(c.req.url).pathname,
371
+ }, 404);
372
+ });
373
+ ```
374
+
375
+ ### Throwing Errors
376
+
377
+ ```typescript
378
+ import { HTTPException } from '@flight-framework/http';
379
+
380
+ app.get('/protected', (c) => {
381
+ if (!c.get('user')) {
382
+ throw new HTTPException(401, 'Unauthorized');
383
+ }
384
+ return c.json({ secret: 'data' });
385
+ });
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Sub-Routers
391
+
392
+ Organize routes into modules:
393
+
394
+ ```typescript
395
+ // routes/users.ts
396
+ import { createServer } from '@flight-framework/http';
397
+
398
+ export const users = createServer();
399
+
400
+ users.get('/', (c) => c.json({ users: [] }));
401
+ users.get('/:id', (c) => c.json({ id: c.params.id }));
402
+ users.post('/', (c) => c.json({ created: true }));
403
+
404
+ // main.ts
405
+ import { createServer } from '@flight-framework/http';
406
+ import { users } from './routes/users';
407
+
408
+ const app = createServer();
409
+
410
+ // Mount sub-router
411
+ app.route('/api/users', users);
412
+
413
+ // Routes:
414
+ // GET /api/users
415
+ // GET /api/users/:id
416
+ // POST /api/users
417
+ ```
418
+
419
+ ---
420
+
421
+ ## Runtime Adapters
422
+
423
+ ### Node.js
424
+
425
+ ```typescript
426
+ import { createServer } from '@flight-framework/http';
427
+ import { serve } from '@flight-framework/http/node';
428
+
429
+ const app = createServer();
430
+
431
+ serve(app, {
432
+ port: 3000,
433
+ hostname: '0.0.0.0',
434
+ });
435
+ ```
436
+
437
+ ### Bun
438
+
439
+ ```typescript
440
+ import { createServer } from '@flight-framework/http';
441
+ import { serve } from '@flight-framework/http/bun';
442
+
443
+ const app = createServer();
444
+
445
+ serve(app, { port: 3000 });
446
+
447
+ // Or use Bun's native API
448
+ Bun.serve({
449
+ port: 3000,
450
+ fetch: app.fetch,
451
+ });
452
+ ```
453
+
454
+ ### Deno
455
+
456
+ ```typescript
457
+ import { createServer } from '@flight-framework/http';
458
+ import { serve } from '@flight-framework/http/deno';
459
+
460
+ const app = createServer();
461
+
462
+ serve(app, { port: 3000 });
463
+
464
+ // Or use Deno's native API
465
+ Deno.serve({ port: 3000 }, app.fetch);
466
+ ```
467
+
468
+ ### Cloudflare Workers
469
+
470
+ ```typescript
471
+ import { createServer } from '@flight-framework/http';
472
+
473
+ const app = createServer();
474
+
475
+ // ... define routes
476
+
477
+ export default {
478
+ fetch: app.fetch,
479
+ };
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Static Files
485
+
486
+ Serve static files from a directory:
487
+
488
+ ```typescript
489
+ import { serveStatic } from '@flight-framework/http/static';
490
+
491
+ // Serve from 'public' directory
492
+ app.use('/static/*', serveStatic({ root: './public' }));
493
+
494
+ // With options
495
+ app.use('/assets/*', serveStatic({
496
+ root: './assets',
497
+ maxAge: 60 * 60 * 24, // 1 day cache
498
+ index: 'index.html',
499
+ }));
500
+ ```
501
+
502
+ ---
503
+
504
+ ## CORS
505
+
506
+ Enable Cross-Origin Resource Sharing:
507
+
508
+ ```typescript
509
+ import { cors } from '@flight-framework/http/cors';
510
+
511
+ // Allow all origins
512
+ app.use(cors());
513
+
514
+ // Specific origins
515
+ app.use(cors({
516
+ origin: 'https://example.com',
517
+ methods: ['GET', 'POST', 'PUT', 'DELETE'],
518
+ headers: ['Content-Type', 'Authorization'],
519
+ credentials: true,
520
+ maxAge: 86400,
521
+ }));
522
+
523
+ // Dynamic origin
524
+ app.use(cors({
525
+ origin: (origin) => {
526
+ return origin.endsWith('.example.com');
527
+ },
528
+ }));
529
+ ```
530
+
531
+ ---
532
+
533
+ ## API Reference
534
+
535
+ ### createServer(options?)
536
+
537
+ Create a new Flight HTTP server.
151
538
 
152
- Handle a Request and return a Response (Web Standard).
539
+ | Option | Type | Default | Description |
540
+ |--------|------|---------|-------------|
541
+ | `strict` | `boolean` | `true` | Strict routing (trailing slash matters) |
542
+ | `getPath` | `function` | - | Custom path extraction |
543
+
544
+ ### Context Methods
545
+
546
+ | Method | Description |
547
+ |--------|-------------|
548
+ | `c.req` | Web Standard Request object |
549
+ | `c.params` | Route parameters |
550
+ | `c.query(name, default?)` | Get query parameter |
551
+ | `c.queries(name)` | Get all values for query param |
552
+ | `c.header(name)` | Get request header |
553
+ | `c.cookie(name)` | Get cookie value |
554
+ | `c.set(key, value)` | Store value in context |
555
+ | `c.get(key)` | Retrieve value from context |
556
+ | `c.json(data, status?)` | JSON response |
557
+ | `c.text(text, status?)` | Text response |
558
+ | `c.html(html, status?)` | HTML response |
559
+ | `c.redirect(url, status?)` | Redirect response |
560
+ | `c.body(body, status?)` | Raw body response |
561
+
562
+ ### App Methods
563
+
564
+ | Method | Description |
565
+ |--------|-------------|
566
+ | `app.get/post/put/delete/patch(path, ...handlers)` | Register route |
567
+ | `app.all(path, ...handlers)` | All HTTP methods |
568
+ | `app.on(methods[], path, ...handlers)` | Specific methods |
569
+ | `app.use(...middleware)` | Add middleware |
570
+ | `app.use(path, ...middleware)` | Path-specific middleware |
571
+ | `app.route(path, subRouter)` | Mount sub-router |
572
+ | `app.notFound(handler)` | Custom 404 handler |
573
+ | `app.onError(handler)` | Custom error handler |
574
+ | `app.fetch(request)` | Handle request (Web Standard) |
575
+
576
+ ---
153
577
 
154
578
  ## License
155
579
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flight-framework/http",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Ultra-fast HTTP server for Flight Framework - Built on Web Standards",
5
5
  "keywords": [
6
6
  "flight",
@@ -54,4 +54,4 @@
54
54
  "typescript": "^5.7.0",
55
55
  "vitest": "^2.0.0"
56
56
  }
57
- }
57
+ }