@wild-framework/http 0.1.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 +27 -0
- package/dist/action.d.ts +23 -0
- package/dist/action.d.ts.map +1 -0
- package/dist/action.js +13 -0
- package/dist/action.js.map +1 -0
- package/dist/errors.d.ts +49 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +77 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +14 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +33 -0
- package/dist/provider.js.map +1 -0
- package/dist/router.d.ts +30 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +58 -0
- package/dist/router.js.map +1 -0
- package/dist/server.d.ts +24 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +54 -0
- package/dist/server.js.map +1 -0
- package/dist/wrap.d.ts +27 -0
- package/dist/wrap.d.ts.map +1 -0
- package/dist/wrap.js +64 -0
- package/dist/wrap.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wild Framework 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,27 @@
|
|
|
1
|
+
# @wild-framework/http
|
|
2
|
+
|
|
3
|
+
Express integration, routing, and error handling for [Wild Framework](https://github.com/your-org/wild-framework).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @wild-framework/http
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Router, action } from "@wild-framework/http";
|
|
15
|
+
|
|
16
|
+
const router = app.resolve(Router);
|
|
17
|
+
|
|
18
|
+
router.get("/users", action(UserController, "index"));
|
|
19
|
+
router.post("/users", CreateUserRequest, action(UserController, "store"));
|
|
20
|
+
router.use(express.json());
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Throwing an `HttpException` (e.g. `NotFoundException`) produces a structured JSON error response.
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
MIT
|
package/dist/action.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tagged handler produced by `action(ControllerClass, "method")`.
|
|
3
|
+
*
|
|
4
|
+
* At request time, the Router resolves the controller from the container
|
|
5
|
+
* and calls the named method.
|
|
6
|
+
*/
|
|
7
|
+
export interface ActionHandler {
|
|
8
|
+
/** The controller class to resolve from the container. */
|
|
9
|
+
readonly controller: abstract new (...args: any[]) => unknown;
|
|
10
|
+
/** The method name to call on the resolved instance. */
|
|
11
|
+
readonly method: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Mark a controller method for lazy resolution.
|
|
15
|
+
*
|
|
16
|
+
* The Router detects `ActionHandler` objects and resolves the controller
|
|
17
|
+
* from the container at request time.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* router.get("/users", action(UserController, "index"));
|
|
21
|
+
*/
|
|
22
|
+
export declare function action<T, K extends keyof T>(controller: abstract new (...args: any[]) => T, method: K & string): ActionHandler;
|
|
23
|
+
//# sourceMappingURL=action.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;IAC9D,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EACvC,UAAU,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAC9C,MAAM,EAAE,CAAC,GAAG,MAAM,GACnB,aAAa,CAEf"}
|
package/dist/action.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mark a controller method for lazy resolution.
|
|
3
|
+
*
|
|
4
|
+
* The Router detects `ActionHandler` objects and resolves the controller
|
|
5
|
+
* from the container at request time.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* router.get("/users", action(UserController, "index"));
|
|
9
|
+
*/
|
|
10
|
+
export function action(controller, method) {
|
|
11
|
+
return { controller, method };
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=action.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action.js","sourceRoot":"","sources":["../src/action.ts"],"names":[],"mappings":"AAaA;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM,CAClB,UAA8C,EAC9C,MAAkB;IAElB,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ZodError } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Base HTTP exception. Produces a structured JSON error response.
|
|
4
|
+
*/
|
|
5
|
+
export declare class HttpException extends Error {
|
|
6
|
+
readonly statusCode: number;
|
|
7
|
+
constructor(statusCode: number, message: string);
|
|
8
|
+
toJSON(): {
|
|
9
|
+
error: string;
|
|
10
|
+
message: string;
|
|
11
|
+
statusCode: number;
|
|
12
|
+
};
|
|
13
|
+
private getStatusText;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 404 — resource not found.
|
|
17
|
+
*/
|
|
18
|
+
export declare class NotFoundException extends HttpException {
|
|
19
|
+
constructor(message?: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 422 — validation failed.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ValidationException extends HttpException {
|
|
25
|
+
readonly errors: ZodError;
|
|
26
|
+
constructor(error: ZodError);
|
|
27
|
+
toJSON(): {
|
|
28
|
+
errors: {
|
|
29
|
+
path: string;
|
|
30
|
+
message: string;
|
|
31
|
+
}[];
|
|
32
|
+
error: string;
|
|
33
|
+
message: string;
|
|
34
|
+
statusCode: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 403 — forbidden.
|
|
39
|
+
*/
|
|
40
|
+
export declare class ForbiddenException extends HttpException {
|
|
41
|
+
constructor(message?: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 401 — unauthorized.
|
|
45
|
+
*/
|
|
46
|
+
export declare class UnauthorizedException extends HttpException {
|
|
47
|
+
constructor(message?: string);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE/C;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAEhB,UAAU,EAAE,MAAM;gBAAlB,UAAU,EAAE,MAAM,EAClC,OAAO,EAAE,MAAM;IAMnB,MAAM;;;;;IAQN,OAAO,CAAC,aAAa;CAWxB;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,aAAa;gBACpC,OAAO,SAAuB;CAI7C;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;IAClD,SAAgB,MAAM,EAAE,QAAQ,CAAC;gBAErB,KAAK,EAAE,QAAQ;IAM3B,MAAM;;;;;;;;;CAST;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,aAAa;gBACrC,OAAO,SAAc;CAIpC;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;gBACxC,OAAO,SAAiB;CAIvC"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base HTTP exception. Produces a structured JSON error response.
|
|
3
|
+
*/
|
|
4
|
+
export class HttpException extends Error {
|
|
5
|
+
statusCode;
|
|
6
|
+
constructor(statusCode, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.name = "HttpException";
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
return {
|
|
13
|
+
error: this.getStatusText(),
|
|
14
|
+
message: this.message,
|
|
15
|
+
statusCode: this.statusCode,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
getStatusText() {
|
|
19
|
+
const map = {
|
|
20
|
+
400: "Bad Request",
|
|
21
|
+
401: "Unauthorized",
|
|
22
|
+
403: "Forbidden",
|
|
23
|
+
404: "Not Found",
|
|
24
|
+
422: "Unprocessable Entity",
|
|
25
|
+
500: "Internal Server Error",
|
|
26
|
+
};
|
|
27
|
+
return map[this.statusCode] ?? "Error";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 404 — resource not found.
|
|
32
|
+
*/
|
|
33
|
+
export class NotFoundException extends HttpException {
|
|
34
|
+
constructor(message = "Resource not found") {
|
|
35
|
+
super(404, message);
|
|
36
|
+
this.name = "NotFoundException";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 422 — validation failed.
|
|
41
|
+
*/
|
|
42
|
+
export class ValidationException extends HttpException {
|
|
43
|
+
errors;
|
|
44
|
+
constructor(error) {
|
|
45
|
+
super(422, "Validation failed");
|
|
46
|
+
this.name = "ValidationException";
|
|
47
|
+
this.errors = error;
|
|
48
|
+
}
|
|
49
|
+
toJSON() {
|
|
50
|
+
return {
|
|
51
|
+
...super.toJSON(),
|
|
52
|
+
errors: this.errors.issues.map((i) => ({
|
|
53
|
+
path: i.path.join("."),
|
|
54
|
+
message: i.message,
|
|
55
|
+
})),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 403 — forbidden.
|
|
61
|
+
*/
|
|
62
|
+
export class ForbiddenException extends HttpException {
|
|
63
|
+
constructor(message = "Forbidden") {
|
|
64
|
+
super(403, message);
|
|
65
|
+
this.name = "ForbiddenException";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 401 — unauthorized.
|
|
70
|
+
*/
|
|
71
|
+
export class UnauthorizedException extends HttpException {
|
|
72
|
+
constructor(message = "Unauthorized") {
|
|
73
|
+
super(401, message);
|
|
74
|
+
this.name = "UnauthorizedException";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEhB;IADpB,YACoB,UAAkB,EAClC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAHC,eAAU,GAAV,UAAU,CAAQ;QAIlC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAChC,CAAC;IAED,MAAM;QACF,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE;YAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC9B,CAAC;IACN,CAAC;IAEO,aAAa;QACjB,MAAM,GAAG,GAA2B;YAChC,GAAG,EAAE,aAAa;YAClB,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,sBAAsB;YAC3B,GAAG,EAAE,uBAAuB;SAC/B,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC;IAC3C,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,OAAO,iBAAkB,SAAQ,aAAa;IAChD,YAAY,OAAO,GAAG,oBAAoB;QACtC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IACpC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IAClC,MAAM,CAAW;IAEjC,YAAY,KAAe;QACvB,KAAK,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,MAAM;QACF,OAAO;YACH,GAAG,KAAK,CAAC,MAAM,EAAE;YACjB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBACtB,OAAO,EAAE,CAAC,CAAC,OAAO;aACrB,CAAC,CAAC;SACN,CAAC;IACN,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,aAAa;IACjD,YAAY,OAAO,GAAG,WAAW;QAC7B,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACrC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,OAAO,qBAAsB,SAAQ,aAAa;IACpD,YAAY,OAAO,GAAG,cAAc;QAChC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACxC,CAAC;CACJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { action } from "./action.js";
|
|
2
|
+
export type { ActionHandler } from "./action.js";
|
|
3
|
+
export { ForbiddenException, HttpException, NotFoundException, UnauthorizedException, ValidationException, } from "./errors.js";
|
|
4
|
+
export { HttpProvider } from "./provider.js";
|
|
5
|
+
export { Router } from "./router.js";
|
|
6
|
+
export { ExpressServer, createErrorHandler } from "./server.js";
|
|
7
|
+
export type { RouteHandler } from "./wrap.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACH,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { action } from "./action.js";
|
|
2
|
+
export { ForbiddenException, HttpException, NotFoundException, UnauthorizedException, ValidationException, } from "./errors.js";
|
|
3
|
+
export { HttpProvider } from "./provider.js";
|
|
4
|
+
export { Router } from "./router.js";
|
|
5
|
+
export { ExpressServer, createErrorHandler } from "./server.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EACH,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Provider, Application } from "@wild-framework/core";
|
|
2
|
+
/**
|
|
3
|
+
* Registers the HTTP layer with the application.
|
|
4
|
+
*
|
|
5
|
+
* - `register()`: creates Express app, Router, ExpressServer. Binds Router
|
|
6
|
+
* into the container and calls `app.setServer()`.
|
|
7
|
+
* - `boot()`: registers the global error handler middleware on the Express app.
|
|
8
|
+
*/
|
|
9
|
+
export declare class HttpProvider implements Provider {
|
|
10
|
+
private expressApp;
|
|
11
|
+
register(app: Application): void;
|
|
12
|
+
boot(_app: Application): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMlE;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,QAAQ;IACzC,OAAO,CAAC,UAAU,CAAwB;IAE1C,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAkBhC,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;CAKhC"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Container } from "@wild-framework/container";
|
|
2
|
+
import express, {} from "express";
|
|
3
|
+
import { Router } from "./router.js";
|
|
4
|
+
import { ExpressServer, createErrorHandler } from "./server.js";
|
|
5
|
+
/**
|
|
6
|
+
* Registers the HTTP layer with the application.
|
|
7
|
+
*
|
|
8
|
+
* - `register()`: creates Express app, Router, ExpressServer. Binds Router
|
|
9
|
+
* into the container and calls `app.setServer()`.
|
|
10
|
+
* - `boot()`: registers the global error handler middleware on the Express app.
|
|
11
|
+
*/
|
|
12
|
+
export class HttpProvider {
|
|
13
|
+
expressApp = null;
|
|
14
|
+
register(app) {
|
|
15
|
+
const container = app.resolve(Container);
|
|
16
|
+
// Express app
|
|
17
|
+
this.expressApp = express();
|
|
18
|
+
// Router — bound into container so providers can add routes
|
|
19
|
+
const router = new Router(container);
|
|
20
|
+
container.singleton(Router, () => router);
|
|
21
|
+
// Mount router on Express (routes defined by providers during register())
|
|
22
|
+
this.expressApp.use(router._getExpressRouter());
|
|
23
|
+
// Server — registered on app for app.listen()
|
|
24
|
+
const server = new ExpressServer(this.expressApp);
|
|
25
|
+
app.setServer(server);
|
|
26
|
+
}
|
|
27
|
+
boot(_app) {
|
|
28
|
+
// Global error handler — must be the last middleware on the Express app.
|
|
29
|
+
// Added during boot phase 2, after all routes have been registered.
|
|
30
|
+
this.expressApp.use(createErrorHandler());
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,OAAO,EAAE,EAAgB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IACb,UAAU,GAAmB,IAAI,CAAC;IAE1C,QAAQ,CAAC,GAAgB;QACrB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,cAAc;QACd,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,CAAC;QAE5B,4DAA4D;QAC5D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;QACrC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;QAE1C,0EAA0E;QAC1E,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAEhD,8CAA8C;QAC9C,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,IAAiB;QAClB,yEAAyE;QACzE,oEAAoE;QACpE,IAAI,CAAC,UAAW,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC/C,CAAC;CACJ"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Router as ExpressRouter, type RequestHandler } from "express";
|
|
2
|
+
import { Container } from "@wild-framework/container";
|
|
3
|
+
import { type RouteHandler } from "./wrap.js";
|
|
4
|
+
/**
|
|
5
|
+
* Wild Framework Router.
|
|
6
|
+
*
|
|
7
|
+
* Wraps Express routing with controller resolution and validation.
|
|
8
|
+
* Routes are defined using `action()` for controller methods and
|
|
9
|
+
* validator classes with Zod schemas.
|
|
10
|
+
*
|
|
11
|
+
* Resolved from the container: `app.resolve(Router)`.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Router {
|
|
14
|
+
private container;
|
|
15
|
+
private expressRouter;
|
|
16
|
+
constructor(container: Container);
|
|
17
|
+
get(path: string, ...handlers: RouteHandler[]): void;
|
|
18
|
+
post(path: string, ...handlers: RouteHandler[]): void;
|
|
19
|
+
put(path: string, ...handlers: RouteHandler[]): void;
|
|
20
|
+
patch(path: string, ...handlers: RouteHandler[]): void;
|
|
21
|
+
delete(path: string, ...handlers: RouteHandler[]): void;
|
|
22
|
+
/**
|
|
23
|
+
* Register global middleware on the router.
|
|
24
|
+
*/
|
|
25
|
+
use(...handlers: RequestHandler[]): void;
|
|
26
|
+
/** @internal — get the underlying Express router. */
|
|
27
|
+
_getExpressRouter(): ExpressRouter;
|
|
28
|
+
private wrapAll;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE3D;;;;;;;;GAQG;AACH,qBAAa,MAAM;IAGH,OAAO,CAAC,SAAS;IAF7B,OAAO,CAAC,aAAa,CAAgB;gBAEjB,SAAS,EAAE,SAAS;IAQxC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIpD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIrD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAIpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAItD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAQvD;;OAEG;IACH,GAAG,CAAC,GAAG,QAAQ,EAAE,cAAc,EAAE,GAAG,IAAI;IAQxC,qDAAqD;IACrD,iBAAiB,IAAI,aAAa;IAIlC,OAAO,CAAC,OAAO;CAGlB"}
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Router as ExpressRouter } from "express";
|
|
2
|
+
import { Container } from "@wild-framework/container";
|
|
3
|
+
import { wrapHandler } from "./wrap.js";
|
|
4
|
+
/**
|
|
5
|
+
* Wild Framework Router.
|
|
6
|
+
*
|
|
7
|
+
* Wraps Express routing with controller resolution and validation.
|
|
8
|
+
* Routes are defined using `action()` for controller methods and
|
|
9
|
+
* validator classes with Zod schemas.
|
|
10
|
+
*
|
|
11
|
+
* Resolved from the container: `app.resolve(Router)`.
|
|
12
|
+
*/
|
|
13
|
+
export class Router {
|
|
14
|
+
container;
|
|
15
|
+
expressRouter;
|
|
16
|
+
constructor(container) {
|
|
17
|
+
this.container = container;
|
|
18
|
+
this.expressRouter = ExpressRouter();
|
|
19
|
+
}
|
|
20
|
+
// -------------------------------------------------------------------
|
|
21
|
+
// HTTP methods
|
|
22
|
+
// -------------------------------------------------------------------
|
|
23
|
+
get(path, ...handlers) {
|
|
24
|
+
this.expressRouter.get(path, ...this.wrapAll(handlers));
|
|
25
|
+
}
|
|
26
|
+
post(path, ...handlers) {
|
|
27
|
+
this.expressRouter.post(path, ...this.wrapAll(handlers));
|
|
28
|
+
}
|
|
29
|
+
put(path, ...handlers) {
|
|
30
|
+
this.expressRouter.put(path, ...this.wrapAll(handlers));
|
|
31
|
+
}
|
|
32
|
+
patch(path, ...handlers) {
|
|
33
|
+
this.expressRouter.patch(path, ...this.wrapAll(handlers));
|
|
34
|
+
}
|
|
35
|
+
delete(path, ...handlers) {
|
|
36
|
+
this.expressRouter.delete(path, ...this.wrapAll(handlers));
|
|
37
|
+
}
|
|
38
|
+
// -------------------------------------------------------------------
|
|
39
|
+
// Middleware
|
|
40
|
+
// -------------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Register global middleware on the router.
|
|
43
|
+
*/
|
|
44
|
+
use(...handlers) {
|
|
45
|
+
this.expressRouter.use(...handlers);
|
|
46
|
+
}
|
|
47
|
+
// -------------------------------------------------------------------
|
|
48
|
+
// Internal
|
|
49
|
+
// -------------------------------------------------------------------
|
|
50
|
+
/** @internal — get the underlying Express router. */
|
|
51
|
+
_getExpressRouter() {
|
|
52
|
+
return this.expressRouter;
|
|
53
|
+
}
|
|
54
|
+
wrapAll(handlers) {
|
|
55
|
+
return handlers.map((h) => wrapHandler(h, this.container));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAuB,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAqB,MAAM,WAAW,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,OAAO,MAAM;IAGK;IAFZ,aAAa,CAAgB;IAErC,YAAoB,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;QACpC,IAAI,CAAC,aAAa,GAAG,aAAa,EAAE,CAAC;IACzC,CAAC;IAED,sEAAsE;IACtE,eAAe;IACf,sEAAsE;IAEtE,GAAG,CAAC,IAAY,EAAE,GAAG,QAAwB;QACzC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,IAAY,EAAE,GAAG,QAAwB;QAC1C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,GAAG,CAAC,IAAY,EAAE,GAAG,QAAwB;QACzC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,IAAY,EAAE,GAAG,QAAwB;QAC3C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,GAAG,QAAwB;QAC5C,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,sEAAsE;IACtE,aAAa;IACb,sEAAsE;IAEtE;;OAEG;IACH,GAAG,CAAC,GAAG,QAA0B;QAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,sEAAsE;IACtE,WAAW;IACX,sEAAsE;IAEtE,qDAAqD;IACrD,iBAAiB;QACb,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAEO,OAAO,CAAC,QAAwB;QACpC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAqB,CAAC;IACnF,CAAC;CACJ"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Server as CoreServer } from "@wild-framework/core";
|
|
2
|
+
import express, { type Express } from "express";
|
|
3
|
+
/**
|
|
4
|
+
* Express-backed implementation of core's `Server` interface.
|
|
5
|
+
*
|
|
6
|
+
* Created by `HttpProvider` and registered via `app.setServer()`.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ExpressServer implements CoreServer {
|
|
9
|
+
private app;
|
|
10
|
+
private server;
|
|
11
|
+
constructor(app: Express);
|
|
12
|
+
listen(port: number): Promise<void>;
|
|
13
|
+
shutdown(): Promise<void>;
|
|
14
|
+
/** @internal */
|
|
15
|
+
_getExpressApp(): Express;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a global error handler middleware for Express.
|
|
19
|
+
*
|
|
20
|
+
* Formats `HttpException` instances as structured JSON.
|
|
21
|
+
* Unexpected errors return 500 with a generic message.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createErrorHandler(): express.ErrorRequestHandler;
|
|
24
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,OAAO,EAAE,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAIhD;;;;GAIG;AACH,qBAAa,aAAc,YAAW,UAAU;IAC5C,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAA2B;gBAE7B,GAAG,EAAE,OAAO;IAIlB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAS/B,gBAAgB;IAChB,cAAc,IAAI,OAAO;CAG5B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,CAehE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import express, {} from "express";
|
|
2
|
+
import { HttpException } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Express-backed implementation of core's `Server` interface.
|
|
5
|
+
*
|
|
6
|
+
* Created by `HttpProvider` and registered via `app.setServer()`.
|
|
7
|
+
*/
|
|
8
|
+
export class ExpressServer {
|
|
9
|
+
app;
|
|
10
|
+
server = null;
|
|
11
|
+
constructor(app) {
|
|
12
|
+
this.app = app;
|
|
13
|
+
}
|
|
14
|
+
async listen(port) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
this.server = this.app.listen(port, () => resolve());
|
|
17
|
+
this.server.on("error", reject);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async shutdown() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
if (!this.server) {
|
|
23
|
+
return resolve();
|
|
24
|
+
}
|
|
25
|
+
this.server.close((err) => (err ? reject(err) : resolve()));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** @internal */
|
|
29
|
+
_getExpressApp() {
|
|
30
|
+
return this.app;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a global error handler middleware for Express.
|
|
35
|
+
*
|
|
36
|
+
* Formats `HttpException` instances as structured JSON.
|
|
37
|
+
* Unexpected errors return 500 with a generic message.
|
|
38
|
+
*/
|
|
39
|
+
export function createErrorHandler() {
|
|
40
|
+
return (err, _req, res, _next) => {
|
|
41
|
+
if (err instanceof HttpException) {
|
|
42
|
+
res.status(err.statusCode).json(err.toJSON());
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Unexpected error — log and return generic 500
|
|
46
|
+
console.error("[wild/http] Unhandled error:", err);
|
|
47
|
+
res.status(500).json({
|
|
48
|
+
error: "Internal Server Error",
|
|
49
|
+
message: "An unexpected error occurred.",
|
|
50
|
+
statusCode: 500,
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,EAAE,EAAgB,MAAM,SAAS,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACd,GAAG,CAAU;IACb,MAAM,GAAsB,IAAI,CAAC;IAEzC,YAAY,GAAY;QACpB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACrB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,QAAQ;QACV,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACf,OAAO,OAAO,EAAE,CAAC;YACrB,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACP,CAAC;IAED,gBAAgB;IAChB,cAAc;QACV,OAAO,IAAI,CAAC,GAAG,CAAC;IACpB,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB;IAC9B,OAAO,CAAC,GAAY,EAAE,IAAqB,EAAE,GAAqB,EAAE,KAA2B,EAAE,EAAE;QAC/F,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YAC/B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9C,OAAO;QACX,CAAC;QAED,gDAAgD;QAChD,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACjB,KAAK,EAAE,uBAAuB;YAC9B,OAAO,EAAE,+BAA+B;YACxC,UAAU,EAAE,GAAG;SAClB,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC"}
|
package/dist/wrap.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from "express";
|
|
2
|
+
import type { ActionHandler } from "./action.js";
|
|
3
|
+
/**
|
|
4
|
+
* Express request handler type (after wrapping).
|
|
5
|
+
*/
|
|
6
|
+
type ExpressHandler = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Any value that can be used as a route handler — raw middleware,
|
|
9
|
+
* ActionHandler, or a validator class (must have `static schema`).
|
|
10
|
+
*/
|
|
11
|
+
export type RouteHandler = ExpressHandler | ActionHandler | (new (...args: any[]) => unknown);
|
|
12
|
+
/**
|
|
13
|
+
* Container-like resolver used by wrapped handlers.
|
|
14
|
+
*/
|
|
15
|
+
interface Resolver {
|
|
16
|
+
resolve<T>(token: unknown): T;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Wrap a route handler for use with Express.
|
|
20
|
+
*
|
|
21
|
+
* - `ActionHandler` → resolved controller + method call
|
|
22
|
+
* - validator class (has `schema`) → validates `req.body`
|
|
23
|
+
* - plain function → passed through directly
|
|
24
|
+
*/
|
|
25
|
+
export declare function wrapHandler(handler: RouteHandler, container: Resolver): ExpressHandler;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=wrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.d.ts","sourceRoot":"","sources":["../src/wrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhG;;;GAGG;AACH,MAAM,MAAM,YAAY,GAClB,cAAc,GACd,aAAa,GACb,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,CAAC;AAExC;;GAEG;AACH,UAAU,QAAQ;IACd,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,GAAG,cAAc,CAatF"}
|
package/dist/wrap.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ValidationException } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Wrap a route handler for use with Express.
|
|
4
|
+
*
|
|
5
|
+
* - `ActionHandler` → resolved controller + method call
|
|
6
|
+
* - validator class (has `schema`) → validates `req.body`
|
|
7
|
+
* - plain function → passed through directly
|
|
8
|
+
*/
|
|
9
|
+
export function wrapHandler(handler, container) {
|
|
10
|
+
// Validator class — detect by checking if it's a constructor with schema
|
|
11
|
+
if (isValidatorClass(handler)) {
|
|
12
|
+
return wrapValidator(handler);
|
|
13
|
+
}
|
|
14
|
+
// ActionHandler — controller method reference
|
|
15
|
+
if (isActionHandler(handler)) {
|
|
16
|
+
return wrapAction(handler, container);
|
|
17
|
+
}
|
|
18
|
+
// Plain Express handler
|
|
19
|
+
return handler;
|
|
20
|
+
}
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Detectors
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
function isValidatorClass(h) {
|
|
25
|
+
return (typeof h === "function" &&
|
|
26
|
+
"schema" in h);
|
|
27
|
+
}
|
|
28
|
+
function isActionHandler(h) {
|
|
29
|
+
return (typeof h === "object" &&
|
|
30
|
+
h !== null &&
|
|
31
|
+
"controller" in h &&
|
|
32
|
+
"method" in h);
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Wrappers
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
function wrapValidator(ValidatorClass) {
|
|
38
|
+
// schema is a static property on the class
|
|
39
|
+
const schema = ValidatorClass.schema;
|
|
40
|
+
return (req, _res, next) => {
|
|
41
|
+
const result = schema.safeParse(req.body);
|
|
42
|
+
if (!result.success) {
|
|
43
|
+
return next(new ValidationException(result.error));
|
|
44
|
+
}
|
|
45
|
+
req.body = result.data;
|
|
46
|
+
next();
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function wrapAction(action, container) {
|
|
50
|
+
return async (req, res, next) => {
|
|
51
|
+
try {
|
|
52
|
+
const instance = container.resolve(action.controller);
|
|
53
|
+
const method = instance[action.method];
|
|
54
|
+
if (typeof method !== "function") {
|
|
55
|
+
throw new Error(`Method "${action.method}" not found on controller "${action.controller.name}".`);
|
|
56
|
+
}
|
|
57
|
+
await method.call(instance, req, res, next);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
next(error);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=wrap.js.map
|
package/dist/wrap.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.js","sourceRoot":"","sources":["../src/wrap.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAwBlD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAqB,EAAE,SAAmB;IAClE,yEAAyE;IACzE,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,8CAA8C;IAC9C,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,wBAAwB;IACxB,OAAO,OAAyB,CAAC;AACrC,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,SAAS,gBAAgB,CAAC,CAAe;IACrC,OAAO,CACH,OAAO,CAAC,KAAK,UAAU;QACvB,QAAQ,IAAI,CAAC,CAChB,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CAAC,CAAe;IACpC,OAAO,CACH,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,YAAY,IAAI,CAAC;QACjB,QAAQ,IAAI,CAAC,CAChB,CAAC;AACN,CAAC;AAED,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,SAAS,aAAa,CAClB,cAA6D;IAE7D,2CAA2C;IAC3C,MAAM,MAAM,GAAI,cAAmD,CAAC,MAAM,CAAC;IAE3E,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,IAAI,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACvB,IAAI,EAAE,CAAC;IACX,CAAC,CAAC;AACN,CAAC;AAED,SAAS,UAAU,CAAC,MAAqB,EAAE,SAAmB;IAC1D,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC5B,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAA6B,CAAC;YAClF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAEvC,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACX,WAAW,MAAM,CAAC,MAAM,8BAA8B,MAAM,CAAC,UAAU,CAAC,IAAI,IAAI,CACnF,CAAC;YACN,CAAC;YAED,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;IACL,CAAC,CAAC;AACN,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wild-framework/http",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Sphah",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/KhandaSoftware/wild-framework.git"
|
|
24
|
+
},
|
|
25
|
+
"description": "Express integration, routing, and error handling for Wild Framework.",
|
|
26
|
+
"keywords": [
|
|
27
|
+
"wild",
|
|
28
|
+
"framework",
|
|
29
|
+
"http",
|
|
30
|
+
"express",
|
|
31
|
+
"router"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"express": "^5.1.0",
|
|
35
|
+
"@wild-framework/core": "0.1.0",
|
|
36
|
+
"@wild-framework/container": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/express": "^5.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"zod": "^3.24.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"clean": "rm -rf dist",
|
|
47
|
+
"test": "vitest run"
|
|
48
|
+
}
|
|
49
|
+
}
|