@fougere/http 0.1.0-alpha.0
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/LICENSE +21 -0
- package/README.md +14 -0
- package/dist/fastify.d.ts +26 -0
- package/dist/fastify.d.ts.map +1 -0
- package/dist/fastify.js +92 -0
- package/dist/fastify.js.map +1 -0
- package/dist/hono.d.ts +27 -0
- package/dist/hono.d.ts.map +1 -0
- package/dist/hono.js +122 -0
- package/dist/hono.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +20 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/router.d.ts +41 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +14 -0
- package/dist/router.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fougere contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @fougere/http
|
|
2
|
+
> HTTP router and middleware
|
|
3
|
+
`HttpRouter` and two levels of middleware: HTTP and application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
```bash
|
|
7
|
+
pnpm add @fougere/http
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Part of [Fougere](https://github.com/chok/fougere) — one schema, a gradient from
|
|
13
|
+
monolith to distributed, the same user code.
|
|
14
|
+
Reference documentation: [the site](https://chok.github.io/fougere/) (en/fr).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fastify adapter — bridges a Fastify server to the HttpRouter interface.
|
|
3
|
+
*/
|
|
4
|
+
import type { HttpRouter } from './router.js';
|
|
5
|
+
interface FastifyLike {
|
|
6
|
+
addHook(hook: string, handler: Function): void;
|
|
7
|
+
get(path: string, handler: Function): void;
|
|
8
|
+
post(path: string, handler: Function): void;
|
|
9
|
+
put(path: string, handler: Function): void;
|
|
10
|
+
patch(path: string, handler: Function): void;
|
|
11
|
+
delete(path: string, handler: Function): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an HttpRouter backed by a Fastify server.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import Fastify from 'fastify'
|
|
18
|
+
* import { createFastifyRouter } from '@fougere/http'
|
|
19
|
+
*
|
|
20
|
+
* const fastify = Fastify()
|
|
21
|
+
* const router = createFastifyRouter(fastify)
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function createFastifyRouter(server: FastifyLike): HttpRouter;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=fastify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAmE,MAAM,aAAa,CAAC;AAE/G,UAAU,WAAW;IACnB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC/C;AA4CD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,CA+CnE"}
|
package/dist/fastify.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const METHOD_MAP = {
|
|
2
|
+
GET: 'get',
|
|
3
|
+
POST: 'post',
|
|
4
|
+
PUT: 'put',
|
|
5
|
+
PATCH: 'patch',
|
|
6
|
+
DELETE: 'delete',
|
|
7
|
+
};
|
|
8
|
+
function buildContext(req) {
|
|
9
|
+
const url = `${req.protocol ?? 'http'}://${req.hostname ?? 'localhost'}${req.url}`;
|
|
10
|
+
const headers = new Headers(req.headers);
|
|
11
|
+
const method = req.method.toUpperCase();
|
|
12
|
+
const hasBody = method !== 'GET' && method !== 'HEAD';
|
|
13
|
+
const request = new Request(url, {
|
|
14
|
+
method,
|
|
15
|
+
headers,
|
|
16
|
+
...(hasBody && req.body ? { body: JSON.stringify(req.body) } : {}),
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
request,
|
|
20
|
+
method: method,
|
|
21
|
+
path: req.url,
|
|
22
|
+
params: req.params ?? {},
|
|
23
|
+
query: req.query ?? {},
|
|
24
|
+
body: async () => req.body ?? {},
|
|
25
|
+
state: {},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function sendResponse(reply, result) {
|
|
29
|
+
if (result.headers) {
|
|
30
|
+
for (const [k, v] of Object.entries(result.headers)) {
|
|
31
|
+
// Fastify handles arrays natively (multiple headers)
|
|
32
|
+
reply.header(k, v);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// `raw` needs no branch here: fastify serializes a string as-is and an object as JSON,
|
|
36
|
+
// and the content-type rides in `headers` — the producer states it, we do not guess.
|
|
37
|
+
reply.status(result.status).send(result.data);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create an HttpRouter backed by a Fastify server.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* import Fastify from 'fastify'
|
|
44
|
+
* import { createFastifyRouter } from '@fougere/http'
|
|
45
|
+
*
|
|
46
|
+
* const fastify = Fastify()
|
|
47
|
+
* const router = createFastifyRouter(fastify)
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function createFastifyRouter(server) {
|
|
51
|
+
const globalMiddlewares = [];
|
|
52
|
+
const scopedMiddlewares = [];
|
|
53
|
+
// Run matching middlewares as an onion chain around the handler
|
|
54
|
+
function runMiddlewares(ctx, handler) {
|
|
55
|
+
const matching = [
|
|
56
|
+
...globalMiddlewares,
|
|
57
|
+
...scopedMiddlewares
|
|
58
|
+
.filter((s) => ctx.path.startsWith(s.path))
|
|
59
|
+
.map((s) => s.mw),
|
|
60
|
+
];
|
|
61
|
+
let index = 0;
|
|
62
|
+
const next = () => {
|
|
63
|
+
if (index < matching.length) {
|
|
64
|
+
return matching[index++](ctx, next);
|
|
65
|
+
}
|
|
66
|
+
return handler(ctx);
|
|
67
|
+
};
|
|
68
|
+
return next();
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
use(...args) {
|
|
72
|
+
const [pathOrMw, maybeMw] = args;
|
|
73
|
+
if (typeof pathOrMw === 'string') {
|
|
74
|
+
// Strip trailing /* — Fastify adapter uses startsWith for prefix matching
|
|
75
|
+
const normalizedPath = pathOrMw.replace(/\/\*$/, '');
|
|
76
|
+
scopedMiddlewares.push({ path: normalizedPath, mw: maybeMw });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
globalMiddlewares.push(pathOrMw);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
on(method, path, handler) {
|
|
83
|
+
const m = METHOD_MAP[method];
|
|
84
|
+
server[m](path, async (req, reply) => {
|
|
85
|
+
const ctx = buildContext(req);
|
|
86
|
+
const result = await runMiddlewares(ctx, handler);
|
|
87
|
+
sendResponse(reply, result);
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastify.js","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"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"}
|
package/dist/hono.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono adapter — bridges a Hono app to the HttpRouter interface.
|
|
3
|
+
*/
|
|
4
|
+
import { type HttpRouter } from './router.js';
|
|
5
|
+
interface HonoLike {
|
|
6
|
+
use(path: string, ...handlers: Function[]): void;
|
|
7
|
+
use(...handlers: Function[]): void;
|
|
8
|
+
get(path: string, handler: Function): void;
|
|
9
|
+
post(path: string, handler: Function): void;
|
|
10
|
+
put(path: string, handler: Function): void;
|
|
11
|
+
patch(path: string, handler: Function): void;
|
|
12
|
+
delete(path: string, handler: Function): void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create an HttpRouter backed by a Hono app.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Hono } from 'hono'
|
|
19
|
+
* import { createHonoRouter } from '@fougere/http'
|
|
20
|
+
*
|
|
21
|
+
* const hono = new Hono()
|
|
22
|
+
* const router = createHonoRouter(hono)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function createHonoRouter(app: HonoLike): HttpRouter;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=hono.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAsB,KAAK,UAAU,EAA4F,MAAM,aAAa,CAAC;AAE5J,UAAU,QAAQ;IAChB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACjD,GAAG,CAAC,GAAG,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IACnC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5C,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC/C;AAyDD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,UAAU,CAgD1D"}
|
package/dist/hono.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono adapter — bridges a Hono app to the HttpRouter interface.
|
|
3
|
+
*/
|
|
4
|
+
import { MalformedJsonError } from './router.js';
|
|
5
|
+
const METHOD_MAP = {
|
|
6
|
+
GET: 'get',
|
|
7
|
+
POST: 'post',
|
|
8
|
+
PUT: 'put',
|
|
9
|
+
PATCH: 'patch',
|
|
10
|
+
DELETE: 'delete',
|
|
11
|
+
};
|
|
12
|
+
function buildContext(c) {
|
|
13
|
+
// Reuse state across middleware/handler calls within the same request
|
|
14
|
+
const state = c.get('_fougereState') ?? {};
|
|
15
|
+
c.set('_fougereState', state);
|
|
16
|
+
return {
|
|
17
|
+
request: c.req.raw,
|
|
18
|
+
method: c.req.method.toUpperCase(),
|
|
19
|
+
path: c.req.path,
|
|
20
|
+
params: c.req.param() ?? {},
|
|
21
|
+
query: c.req.query() ?? {},
|
|
22
|
+
body: async () => {
|
|
23
|
+
const method = c.req.method.toUpperCase();
|
|
24
|
+
const contentType = c.req.header?.('content-type') ?? c.req.raw?.headers?.get?.('content-type') ?? '';
|
|
25
|
+
if (method === 'GET' || method === 'HEAD' || !contentType.toLowerCase().includes('json'))
|
|
26
|
+
return {};
|
|
27
|
+
try {
|
|
28
|
+
return await c.req.json();
|
|
29
|
+
}
|
|
30
|
+
catch (cause) {
|
|
31
|
+
throw new MalformedJsonError({ cause });
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
state,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function sendResponse(c, result) {
|
|
38
|
+
if (result.headers) {
|
|
39
|
+
for (const [k, v] of Object.entries(result.headers)) {
|
|
40
|
+
if (Array.isArray(v)) {
|
|
41
|
+
for (const item of v)
|
|
42
|
+
c.header(k, item, { append: true });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
c.header(k, v);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (result.data === undefined || result.data === null) {
|
|
50
|
+
return c.body(null, result.status);
|
|
51
|
+
}
|
|
52
|
+
if (result.raw) {
|
|
53
|
+
return c.body(result.data, result.status);
|
|
54
|
+
}
|
|
55
|
+
return c.json(result.data, result.status);
|
|
56
|
+
}
|
|
57
|
+
function malformedJsonResponse(c) {
|
|
58
|
+
return sendResponse(c, { status: 400, data: { code: 'BAD_REQUEST', message: 'Malformed JSON body' } });
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create an HttpRouter backed by a Hono app.
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import { Hono } from 'hono'
|
|
65
|
+
* import { createHonoRouter } from '@fougere/http'
|
|
66
|
+
*
|
|
67
|
+
* const hono = new Hono()
|
|
68
|
+
* const router = createHonoRouter(hono)
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function createHonoRouter(app) {
|
|
72
|
+
return {
|
|
73
|
+
use(...args) {
|
|
74
|
+
const [pathOrMw, maybeMw] = args;
|
|
75
|
+
const path = typeof pathOrMw === 'string' ? pathOrMw : undefined;
|
|
76
|
+
const mw = (typeof pathOrMw === 'function' ? pathOrMw : maybeMw);
|
|
77
|
+
const honoMiddleware = async (c, next) => {
|
|
78
|
+
try {
|
|
79
|
+
const ctx = buildContext(c);
|
|
80
|
+
const result = await mw(ctx, async () => {
|
|
81
|
+
await next();
|
|
82
|
+
// After next(), Hono has already set the response — return a passthrough
|
|
83
|
+
return { status: c.res.status, data: null };
|
|
84
|
+
});
|
|
85
|
+
// If the middleware returned a custom response (short-circuit), send it
|
|
86
|
+
if (result.data !== null) {
|
|
87
|
+
return sendResponse(c, result);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
if (err instanceof MalformedJsonError)
|
|
92
|
+
return malformedJsonResponse(c);
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
if (path) {
|
|
97
|
+
// Hono requires /* suffix for prefix matching on middleware
|
|
98
|
+
const honoPath = path.endsWith('/*') ? path : `${path}/*`;
|
|
99
|
+
app.use(honoPath, honoMiddleware);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
app.use(honoMiddleware);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
on(method, path, handler) {
|
|
106
|
+
const m = METHOD_MAP[method];
|
|
107
|
+
app[m](path, async (c) => {
|
|
108
|
+
const ctx = buildContext(c);
|
|
109
|
+
try {
|
|
110
|
+
const result = await handler(ctx);
|
|
111
|
+
return sendResponse(c, result);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
if (err instanceof MalformedJsonError)
|
|
115
|
+
return malformedJsonResponse(c);
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=hono.js.map
|
package/dist/hono.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { HttpMethod, RequestContext, ResponseResult, Handler, Next, Middleware, HttpRouter, } from './router.js';
|
|
2
|
+
export { MalformedJsonError } from './router.js';
|
|
3
|
+
export { createHonoRouter } from './hono.js';
|
|
4
|
+
export { createFastifyRouter } from './fastify.js';
|
|
5
|
+
export { httpLogger } from './logger.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,OAAO,EACP,IAAI,EACJ,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP request logger middleware.
|
|
3
|
+
*/
|
|
4
|
+
import type { Middleware } from './router.js';
|
|
5
|
+
interface LoggerLike {
|
|
6
|
+
info(msg: string, ...args: unknown[]): void;
|
|
7
|
+
warn(msg: string, ...args: unknown[]): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* HTTP request logger — logs method, path, status, and duration.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { httpLogger } from '@fougere/http'
|
|
14
|
+
*
|
|
15
|
+
* router.use(httpLogger(logger))
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function httpLogger(logger: LoggerLike): Middleware;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,UAAU;IAClB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC7C;AASD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAczD"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const STATUS_COLORS = {
|
|
2
|
+
'2': '\x1b[32m', // green
|
|
3
|
+
'3': '\x1b[36m', // cyan
|
|
4
|
+
'4': '\x1b[33m', // yellow
|
|
5
|
+
'5': '\x1b[31m', // red
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* HTTP request logger — logs method, path, status, and duration.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { httpLogger } from '@fougere/http'
|
|
12
|
+
*
|
|
13
|
+
* router.use(httpLogger(logger))
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function httpLogger(logger) {
|
|
17
|
+
return async (ctx, next) => {
|
|
18
|
+
const start = performance.now();
|
|
19
|
+
const result = await next();
|
|
20
|
+
const ms = (performance.now() - start).toFixed(1);
|
|
21
|
+
const method = ctx.method.padEnd(7);
|
|
22
|
+
const status = result.status;
|
|
23
|
+
const log = status >= 400 ? 'warn' : 'info';
|
|
24
|
+
logger[log](`${method} ${ctx.path} ${status} ${ms}ms`);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAUA,MAAM,aAAa,GAA2B;IAC5C,GAAG,EAAE,UAAU,EAAE,QAAQ;IACzB,GAAG,EAAE,UAAU,EAAE,OAAO;IACxB,GAAG,EAAE,UAAU,EAAE,SAAS;IAC1B,GAAG,EAAE,UAAU,EAAE,MAAM;CACxB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAElD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QAE5C,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC;QAEvD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fougere/http — framework-agnostic HTTP router interface.
|
|
3
|
+
*
|
|
4
|
+
* Adapters (Hono, Fastify, etc.) implement HttpRouter.
|
|
5
|
+
* Consumers (schema-rest, schema-graphql) program against it.
|
|
6
|
+
*/
|
|
7
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
8
|
+
export interface RequestContext {
|
|
9
|
+
/** The original Web Standard Request — source of truth. */
|
|
10
|
+
request: Request;
|
|
11
|
+
method: HttpMethod;
|
|
12
|
+
path: string;
|
|
13
|
+
params: Record<string, string>;
|
|
14
|
+
query: Record<string, string>;
|
|
15
|
+
body: () => Promise<unknown>;
|
|
16
|
+
/** Extensible bag — middlewares deposit data here (auth, session, etc.). */
|
|
17
|
+
state: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface ResponseResult {
|
|
20
|
+
status: number;
|
|
21
|
+
data: unknown;
|
|
22
|
+
headers?: Record<string, string | string[]>;
|
|
23
|
+
/** Send data as raw body (not JSON-serialized). Use for HTML, XML, CSV, plain text, etc. */
|
|
24
|
+
raw?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Raised by an adapter when a request claims JSON but cannot be parsed. */
|
|
27
|
+
export declare class MalformedJsonError extends Error {
|
|
28
|
+
constructor(options?: ErrorOptions);
|
|
29
|
+
}
|
|
30
|
+
export type Handler = (ctx: RequestContext) => Promise<ResponseResult>;
|
|
31
|
+
export type Next = () => Promise<ResponseResult>;
|
|
32
|
+
export type Middleware = (ctx: RequestContext, next: Next) => Promise<ResponseResult>;
|
|
33
|
+
export interface HttpRouter {
|
|
34
|
+
/** Register a global middleware. */
|
|
35
|
+
use(middleware: Middleware): void;
|
|
36
|
+
/** Register a middleware scoped to a path prefix. */
|
|
37
|
+
use(path: string, middleware: Middleware): void;
|
|
38
|
+
/** Register a route handler. */
|
|
39
|
+
on(method: HttpMethod, path: string, handler: Handler): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,4FAA4F;IAC5F,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,4EAA4E;AAC5E,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAO,CAAC,EAAE,YAAY,EAGjC;CACF;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AACvE,MAAM,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAC;AACjD,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAEtF,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAClC,qDAAqD;IACrD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAChD,gCAAgC;IAChC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9D"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fougere/http — framework-agnostic HTTP router interface.
|
|
3
|
+
*
|
|
4
|
+
* Adapters (Hono, Fastify, etc.) implement HttpRouter.
|
|
5
|
+
* Consumers (schema-rest, schema-graphql) program against it.
|
|
6
|
+
*/
|
|
7
|
+
/** Raised by an adapter when a request claims JSON but cannot be parsed. */
|
|
8
|
+
export class MalformedJsonError extends Error {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super('Malformed JSON body', options);
|
|
11
|
+
this.name = 'MalformedJsonError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,4EAA4E;AAC5E,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAsB;QAChC,KAAK,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fougere/http",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "HTTP router and middleware.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/chok/fougere.git",
|
|
9
|
+
"directory": "packages/http"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "dist/index.js",
|
|
13
|
+
"types": "dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.19.15",
|
|
25
|
+
"vitest": "^4.1.0"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rm -rf dist && tsc",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
}
|
|
36
|
+
}
|