@bejibun/core 0.1.64 → 0.1.66
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/CHANGELOG.md +45 -0
- package/builders/RouterBuilder.d.ts +19 -13
- package/builders/RouterBuilder.js +195 -33
- package/facades/Router.d.ts +16 -12
- package/facades/Router.js +7 -9
- package/package.json +1 -1
- package/server.d.ts +6 -1
- package/server.js +51 -42
- package/types/router.d.ts +16 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,51 @@ All notable changes to this project will be documented in this file.
|
|
|
3
3
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
## [v0.1.66](https://github.com/crenata/bejibun-core/compare/v0.1.65...v0.1.66) - 2025-12-31
|
|
7
|
+
|
|
8
|
+
### 🩹 Fixes
|
|
9
|
+
|
|
10
|
+
### 📖 Changes
|
|
11
|
+
#### What's New :
|
|
12
|
+
- Added `Router.resource()`
|
|
13
|
+
|
|
14
|
+
Single line code that automatically generates a full set of CRUD.
|
|
15
|
+
|
|
16
|
+
#### How to use?
|
|
17
|
+
```ts
|
|
18
|
+
import Router from "@bejibun/core/facades/Router";
|
|
19
|
+
import YourController from "@/app/controllers/YourController";
|
|
20
|
+
|
|
21
|
+
Router.resource("path", YourController);
|
|
22
|
+
Router.resource("path", YourController, {
|
|
23
|
+
only: ["index", "store"] // "index" | "store" | "show" | "update" | "destroy"
|
|
24
|
+
});
|
|
25
|
+
Router.resource("path", YourController, {
|
|
26
|
+
except: ["index", "store"] // "index" | "store" | "show" | "update" | "destroy"
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### ❤️Contributors
|
|
31
|
+
- Havea Crenata ([@crenata](https://github.com/crenata))
|
|
32
|
+
|
|
33
|
+
**Full Changelog**: https://github.com/crenata/bejibun-core/blob/master/CHANGELOG.md
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [v0.1.65](https://github.com/crenata/bejibun-core/compare/v0.1.64...v0.1.65) - 2025-12-29
|
|
38
|
+
|
|
39
|
+
### 🩹 Fixes
|
|
40
|
+
- Router namespace on group - [#6](https://github.com/crenata/bejibun-core/issues/6)
|
|
41
|
+
|
|
42
|
+
### 📖 Changes
|
|
43
|
+
|
|
44
|
+
### ❤️Contributors
|
|
45
|
+
- Havea Crenata ([@crenata](https://github.com/crenata))
|
|
46
|
+
|
|
47
|
+
**Full Changelog**: https://github.com/crenata/bejibun-core/blob/master/CHANGELOG.md
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
6
51
|
## [v0.1.64](https://github.com/crenata/bejibun-core/compare/v0.1.61...v0.1.64) - 2025-12-25
|
|
7
52
|
|
|
8
53
|
### 🩹 Fixes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { TFacilitator, TPaywall, TX402Config } from "@bejibun/x402";
|
|
2
2
|
import type { IMiddleware } from "../types/middleware";
|
|
3
|
-
import type { HandlerType, ResourceAction, RouterGroup } from "../types/router";
|
|
3
|
+
import type { HandlerType, ResourceAction, Route, RouterGroup } from "../types/router";
|
|
4
4
|
import HttpMethodEnum from "@bejibun/utils/enums/HttpMethodEnum";
|
|
5
|
+
import BaseController from "../bases/BaseController";
|
|
5
6
|
export interface ResourceOptions {
|
|
6
7
|
only?: Array<ResourceAction>;
|
|
7
8
|
except?: Array<ResourceAction>;
|
|
@@ -14,21 +15,26 @@ export default class RouterBuilder {
|
|
|
14
15
|
middleware(...middlewares: Array<IMiddleware>): RouterBuilder;
|
|
15
16
|
namespace(baseNamespace: string): RouterBuilder;
|
|
16
17
|
x402(config?: TX402Config, facilitatorConfig?: TFacilitator, paywallConfig?: TPaywall): RouterBuilder;
|
|
17
|
-
group(routes:
|
|
18
|
-
|
|
19
|
-
buildSingle(method: HttpMethodEnum, path: string, handler: string | HandlerType):
|
|
20
|
-
connect(path: string, handler: string | HandlerType):
|
|
21
|
-
delete(path: string, handler: string | HandlerType):
|
|
22
|
-
get(path: string, handler: string | HandlerType):
|
|
23
|
-
head(path: string, handler: string | HandlerType):
|
|
24
|
-
options(path: string, handler: string | HandlerType):
|
|
25
|
-
patch(path: string, handler: string | HandlerType):
|
|
26
|
-
post(path: string, handler: string | HandlerType):
|
|
27
|
-
put(path: string, handler: string | HandlerType):
|
|
28
|
-
trace(path: string, handler: string | HandlerType):
|
|
18
|
+
group(routes: Route | Array<Route> | RouterGroup): RouterGroup | Array<RouterGroup>;
|
|
19
|
+
resource(path: string, controller: typeof BaseController, options?: ResourceOptions): RouterGroup;
|
|
20
|
+
buildSingle(method: HttpMethodEnum, path: string, handler: string | HandlerType): Route;
|
|
21
|
+
connect(path: string, handler: string | HandlerType): Route;
|
|
22
|
+
delete(path: string, handler: string | HandlerType): Route;
|
|
23
|
+
get(path: string, handler: string | HandlerType): Route;
|
|
24
|
+
head(path: string, handler: string | HandlerType): Route;
|
|
25
|
+
options(path: string, handler: string | HandlerType): Route;
|
|
26
|
+
patch(path: string, handler: string | HandlerType): Route;
|
|
27
|
+
post(path: string, handler: string | HandlerType): Route;
|
|
28
|
+
put(path: string, handler: string | HandlerType): Route;
|
|
29
|
+
trace(path: string, handler: string | HandlerType): Route;
|
|
29
30
|
match(methods: Array<HttpMethodEnum>, path: string, handler: string | HandlerType): RouterGroup;
|
|
30
31
|
any(path: string, handler: string | HandlerType): RouterGroup;
|
|
32
|
+
serialize(routes: Route | Array<Route> | RouterGroup | Array<RouterGroup>): RouterGroup;
|
|
33
|
+
private mergeRoutes;
|
|
31
34
|
private joinPaths;
|
|
32
35
|
private resolveControllerString;
|
|
33
36
|
private resolveIncludedActions;
|
|
37
|
+
private hasRaw;
|
|
38
|
+
private isMethodMap;
|
|
39
|
+
private applyGroup;
|
|
34
40
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import App from "@bejibun/app";
|
|
2
|
-
import
|
|
2
|
+
import Logger from "@bejibun/logger";
|
|
3
|
+
import { defineValue, isEmpty, isModuleExists, isNotEmpty } from "@bejibun/utils";
|
|
3
4
|
import HttpMethodEnum from "@bejibun/utils/enums/HttpMethodEnum";
|
|
4
5
|
import Enum from "@bejibun/utils/facades/Enum";
|
|
5
6
|
import path from "path";
|
|
@@ -28,67 +29,124 @@ export default class RouterBuilder {
|
|
|
28
29
|
return this;
|
|
29
30
|
}
|
|
30
31
|
group(routes) {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
const rawGroups = [];
|
|
33
|
+
let routeGroups = {};
|
|
34
|
+
if (this.hasRaw(routes)) {
|
|
35
|
+
const routeList = Array.isArray(routes) ? routes.flat() : [routes];
|
|
36
|
+
const routerGroups = routeList.filter((value) => !this.hasRaw(value));
|
|
37
|
+
const rawRoutes = routeList.filter((value) => this.hasRaw(value));
|
|
38
|
+
const newRoutes = {};
|
|
39
|
+
for (const route of rawRoutes) {
|
|
40
|
+
const middlewares = this.middlewares.concat(defineValue(route.raw.middlewares, []));
|
|
41
|
+
const effectiveNamespace = defineValue(this.baseNamespace, route.raw.namespace);
|
|
42
|
+
const cleanPath = this.joinPaths(defineValue(route.raw.prefix, this.basePath), route.raw.path);
|
|
43
|
+
let resolvedHandler = typeof route.raw.handler === "string" ?
|
|
44
|
+
this.resolveControllerString(route.raw.handler, effectiveNamespace) :
|
|
45
|
+
route.raw.handler;
|
|
46
|
+
for (const middleware of [...middlewares].reverse()) {
|
|
47
|
+
resolvedHandler = middleware.handle(resolvedHandler);
|
|
44
48
|
}
|
|
45
49
|
if (isEmpty(newRoutes[cleanPath]))
|
|
46
50
|
newRoutes[cleanPath] = {};
|
|
47
|
-
Object.assign(newRoutes[cleanPath],
|
|
51
|
+
Object.assign(newRoutes[cleanPath], {
|
|
52
|
+
[route.raw.method]: resolvedHandler
|
|
53
|
+
});
|
|
54
|
+
route.raw.middlewares = middlewares;
|
|
55
|
+
route.raw.namespace = effectiveNamespace;
|
|
56
|
+
route.raw.path = cleanPath;
|
|
57
|
+
rawGroups.push(route);
|
|
48
58
|
}
|
|
59
|
+
routeGroups = Object.assign({}, ...routerGroups.map((value) => this.applyGroup(value)), newRoutes);
|
|
60
|
+
}
|
|
61
|
+
if (isNotEmpty(routeGroups))
|
|
62
|
+
return {
|
|
63
|
+
raws: rawGroups,
|
|
64
|
+
routes: routeGroups
|
|
65
|
+
};
|
|
66
|
+
if (isEmpty(routes))
|
|
67
|
+
return {};
|
|
68
|
+
if (Array.isArray(routes)) {
|
|
69
|
+
return routes.map((value) => {
|
|
70
|
+
if (isNotEmpty(value.raws))
|
|
71
|
+
return value.raws;
|
|
72
|
+
return value;
|
|
73
|
+
})
|
|
74
|
+
.flat()
|
|
75
|
+
.map((route) => this.applyGroup(route));
|
|
49
76
|
}
|
|
50
|
-
return
|
|
77
|
+
return this.applyGroup(routes);
|
|
51
78
|
}
|
|
52
|
-
|
|
79
|
+
resource(path, controller, options) {
|
|
80
|
+
const ClassController = new controller();
|
|
81
|
+
const cleanPath = this.joinPaths(this.basePath, path);
|
|
53
82
|
const allRoutes = {
|
|
54
|
-
|
|
83
|
+
[cleanPath]: {
|
|
55
84
|
GET: "index",
|
|
56
85
|
POST: "store"
|
|
57
86
|
},
|
|
58
|
-
|
|
87
|
+
[`${cleanPath}/:id`]: {
|
|
59
88
|
GET: "show",
|
|
60
89
|
PUT: "update",
|
|
61
90
|
DELETE: "destroy"
|
|
62
91
|
}
|
|
63
92
|
};
|
|
64
93
|
const includedActions = this.resolveIncludedActions(options);
|
|
65
|
-
const
|
|
94
|
+
const raws = [];
|
|
95
|
+
const routes = {};
|
|
66
96
|
for (const path in allRoutes) {
|
|
67
97
|
const methods = allRoutes[path];
|
|
68
|
-
const
|
|
98
|
+
const methodMap = {};
|
|
69
99
|
for (const method in methods) {
|
|
70
100
|
const action = methods[method];
|
|
71
|
-
|
|
72
|
-
|
|
101
|
+
let handler = ClassController[action];
|
|
102
|
+
if (includedActions.has(action) && isNotEmpty(handler)) {
|
|
103
|
+
raws.push({
|
|
104
|
+
raw: {
|
|
105
|
+
prefix: this.basePath,
|
|
106
|
+
middlewares: [],
|
|
107
|
+
namespace: this.baseNamespace,
|
|
108
|
+
method,
|
|
109
|
+
path,
|
|
110
|
+
handler
|
|
111
|
+
},
|
|
112
|
+
route: {
|
|
113
|
+
[path]: {
|
|
114
|
+
[method]: handler
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
73
118
|
}
|
|
74
119
|
}
|
|
75
|
-
if (Object.keys(
|
|
76
|
-
|
|
120
|
+
if (Object.keys(methodMap).length > 0) {
|
|
121
|
+
routes[path] = methodMap;
|
|
77
122
|
}
|
|
78
123
|
}
|
|
79
|
-
return this.
|
|
124
|
+
return this.applyGroup({
|
|
125
|
+
raws,
|
|
126
|
+
routes
|
|
127
|
+
});
|
|
80
128
|
}
|
|
81
129
|
buildSingle(method, path, handler) {
|
|
82
130
|
const cleanPath = this.joinPaths(this.basePath, path);
|
|
83
131
|
let resolvedHandler = typeof handler === "string" ?
|
|
84
132
|
this.resolveControllerString(handler) :
|
|
85
133
|
handler;
|
|
86
|
-
for (const middleware of this.middlewares) {
|
|
134
|
+
for (const middleware of [...this.middlewares].reverse()) {
|
|
87
135
|
resolvedHandler = middleware.handle(resolvedHandler);
|
|
88
136
|
}
|
|
89
137
|
return {
|
|
90
|
-
|
|
91
|
-
|
|
138
|
+
raw: {
|
|
139
|
+
prefix: this.basePath,
|
|
140
|
+
middlewares: this.middlewares,
|
|
141
|
+
namespace: this.baseNamespace,
|
|
142
|
+
method,
|
|
143
|
+
path,
|
|
144
|
+
handler
|
|
145
|
+
},
|
|
146
|
+
route: {
|
|
147
|
+
[cleanPath]: {
|
|
148
|
+
[method]: resolvedHandler
|
|
149
|
+
}
|
|
92
150
|
}
|
|
93
151
|
};
|
|
94
152
|
}
|
|
@@ -122,7 +180,7 @@ export default class RouterBuilder {
|
|
|
122
180
|
match(methods, path, handler) {
|
|
123
181
|
const routeMap = {};
|
|
124
182
|
for (const method of methods) {
|
|
125
|
-
const single = this.buildSingle(method, path, handler);
|
|
183
|
+
const single = this.buildSingle(method, path, handler).route;
|
|
126
184
|
const fullPath = Object.keys(single)[0];
|
|
127
185
|
const handlers = single[fullPath];
|
|
128
186
|
if (isEmpty(routeMap[fullPath]))
|
|
@@ -134,18 +192,60 @@ export default class RouterBuilder {
|
|
|
134
192
|
any(path, handler) {
|
|
135
193
|
return this.match(Enum.setEnums(HttpMethodEnum).toArray().map((value) => value.value), path, handler);
|
|
136
194
|
}
|
|
195
|
+
serialize(routes) {
|
|
196
|
+
if (Array.isArray(routes)) {
|
|
197
|
+
if (this.hasRaw(routes))
|
|
198
|
+
routes = routes.map((value) => value.route);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
if (this.hasRaw(routes))
|
|
202
|
+
routes = routes.route;
|
|
203
|
+
}
|
|
204
|
+
const mergedRoutes = this.mergeRoutes(routes);
|
|
205
|
+
if (Array.isArray(mergedRoutes))
|
|
206
|
+
return Object.assign({}, ...mergedRoutes);
|
|
207
|
+
return mergedRoutes;
|
|
208
|
+
}
|
|
209
|
+
mergeRoutes(routes) {
|
|
210
|
+
const merged = {};
|
|
211
|
+
const routeEntries = Array.isArray(routes) ?
|
|
212
|
+
routes :
|
|
213
|
+
Object.entries(routes).map(([path, methods]) => ({
|
|
214
|
+
[path]: methods
|
|
215
|
+
}));
|
|
216
|
+
for (const route of routeEntries) {
|
|
217
|
+
for (const [path, methods] of Object.entries(route)) {
|
|
218
|
+
if (isEmpty(merged[path]))
|
|
219
|
+
merged[path] = {};
|
|
220
|
+
for (const [method, handler] of Object.entries(methods)) {
|
|
221
|
+
if (isNotEmpty(merged[path][method]))
|
|
222
|
+
Logger.setContext("Router").warn(`Duplicate route: ${method} ${path} - overwriting.`);
|
|
223
|
+
merged[path][method] = handler;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return merged;
|
|
228
|
+
}
|
|
137
229
|
joinPaths(base, path) {
|
|
138
230
|
base = base.replace(/\/+$/, "");
|
|
139
231
|
path = path.replace(/^\/+/, "");
|
|
140
232
|
return `/${[base, path].filter(Boolean).join("/")}`;
|
|
141
233
|
}
|
|
142
|
-
resolveControllerString(definition) {
|
|
234
|
+
resolveControllerString(definition, overrideNamespace) {
|
|
143
235
|
const [controllerName, methodName] = definition.split("@");
|
|
144
236
|
if (isEmpty(controllerName) || isEmpty(methodName)) {
|
|
145
237
|
throw new RouterException(`Invalid router controller definition: ${definition}.`);
|
|
146
238
|
}
|
|
147
|
-
const controllerPath = path.resolve(App.Path.rootPath(), this.baseNamespace);
|
|
148
|
-
|
|
239
|
+
const controllerPath = path.resolve(App.Path.rootPath(), defineValue(overrideNamespace, this.baseNamespace));
|
|
240
|
+
let location = null;
|
|
241
|
+
try {
|
|
242
|
+
location = Bun.resolveSync(`./${controllerName}.ts`, controllerPath);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return async () => {
|
|
246
|
+
throw new RouterException(`Invalid router for controller location [${controllerPath}]`);
|
|
247
|
+
};
|
|
248
|
+
}
|
|
149
249
|
let ControllerClass;
|
|
150
250
|
try {
|
|
151
251
|
ControllerClass = require(location).default;
|
|
@@ -180,4 +280,66 @@ export default class RouterBuilder {
|
|
|
180
280
|
}
|
|
181
281
|
return new Set(all);
|
|
182
282
|
}
|
|
283
|
+
hasRaw(routes) {
|
|
284
|
+
if (Array.isArray(routes))
|
|
285
|
+
return routes.flat().some(route => isNotEmpty(route) && "raw" in route);
|
|
286
|
+
return (isNotEmpty(routes) &&
|
|
287
|
+
typeof routes === "object" &&
|
|
288
|
+
"raw" in routes);
|
|
289
|
+
}
|
|
290
|
+
isMethodMap(value) {
|
|
291
|
+
return (isNotEmpty(value) &&
|
|
292
|
+
typeof value === "object" &&
|
|
293
|
+
Object.values(value).every(v => typeof v === "function"));
|
|
294
|
+
}
|
|
295
|
+
applyGroup(route) {
|
|
296
|
+
if (isEmpty(route))
|
|
297
|
+
return route;
|
|
298
|
+
if (this.hasRaw(route)) {
|
|
299
|
+
const routeList = Array.isArray(route) ? route.flat() : [route];
|
|
300
|
+
const rawRoutes = routeList.filter((value) => this.hasRaw(value));
|
|
301
|
+
const newRoutes = {};
|
|
302
|
+
for (const route of rawRoutes) {
|
|
303
|
+
const middlewares = route.raw.middlewares.concat(defineValue(this.middlewares, []));
|
|
304
|
+
const cleanPath = this.joinPaths(defineValue(route.raw.prefix, this.basePath), route.raw.path);
|
|
305
|
+
const effectiveNamespace = defineValue(this.baseNamespace === "app/controllers" ?
|
|
306
|
+
null :
|
|
307
|
+
this.baseNamespace, route.raw.namespace);
|
|
308
|
+
let resolvedHandler = typeof route.raw.handler === "string" ?
|
|
309
|
+
this.resolveControllerString(route.raw.handler, effectiveNamespace) :
|
|
310
|
+
route.raw.handler;
|
|
311
|
+
for (const middleware of [...middlewares].reverse()) {
|
|
312
|
+
resolvedHandler = middleware.handle(resolvedHandler);
|
|
313
|
+
}
|
|
314
|
+
if (isEmpty(newRoutes[cleanPath]))
|
|
315
|
+
newRoutes[cleanPath] = {};
|
|
316
|
+
Object.assign(newRoutes[cleanPath], {
|
|
317
|
+
[route.raw.method]: resolvedHandler
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return newRoutes;
|
|
321
|
+
}
|
|
322
|
+
const result = {};
|
|
323
|
+
for (const [key, value] of Object.entries(route)) {
|
|
324
|
+
const newKey = key.startsWith("/") ? this.joinPaths(this.basePath, key) : key;
|
|
325
|
+
if (this.isMethodMap(value)) {
|
|
326
|
+
const wrappedMethods = {};
|
|
327
|
+
for (const [method, handler] of Object.entries(value)) {
|
|
328
|
+
let resolvedHandler = handler;
|
|
329
|
+
for (const middleware of [...this.middlewares].reverse()) {
|
|
330
|
+
resolvedHandler = middleware.handle(resolvedHandler);
|
|
331
|
+
}
|
|
332
|
+
wrappedMethods[method] = resolvedHandler;
|
|
333
|
+
}
|
|
334
|
+
result[newKey] = wrappedMethods;
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (isNotEmpty(value) && typeof value === "object") {
|
|
338
|
+
result[newKey] = this.applyGroup(value);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
result[newKey] = value;
|
|
342
|
+
}
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
183
345
|
}
|
package/facades/Router.d.ts
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
|
+
import type { ResourceOptions } from "../builders/RouterBuilder";
|
|
1
2
|
import type { IMiddleware } from "../types/middleware";
|
|
2
3
|
import type { HandlerType, RouterGroup } from "../types/router";
|
|
3
4
|
import HttpMethodEnum from "@bejibun/utils/enums/HttpMethodEnum";
|
|
4
|
-
import
|
|
5
|
+
import BaseController from "../bases/BaseController";
|
|
6
|
+
import RouterBuilder from "../builders/RouterBuilder";
|
|
7
|
+
import { Route } from "../types/router";
|
|
5
8
|
export default class Router {
|
|
6
9
|
static prefix(basePath: string): RouterBuilder;
|
|
7
10
|
static middleware(...middlewares: Array<IMiddleware>): RouterBuilder;
|
|
8
11
|
static namespace(baseNamespace: string): RouterBuilder;
|
|
9
12
|
static x402(): RouterBuilder;
|
|
10
|
-
static
|
|
11
|
-
static group(routes:
|
|
12
|
-
static connect(path: string, handler: string | HandlerType):
|
|
13
|
-
static delete(path: string, handler: string | HandlerType):
|
|
14
|
-
static get(path: string, handler: string | HandlerType):
|
|
15
|
-
static head(path: string, handler: string | HandlerType):
|
|
16
|
-
static options(path: string, handler: string | HandlerType):
|
|
17
|
-
static patch(path: string, handler: string | HandlerType):
|
|
18
|
-
static post(path: string, handler: string | HandlerType):
|
|
19
|
-
static put(path: string, handler: string | HandlerType):
|
|
20
|
-
static trace(path: string, handler: string | HandlerType):
|
|
13
|
+
static resource(path: string, controller: typeof BaseController, options?: ResourceOptions): RouterGroup;
|
|
14
|
+
static group(routes: Route | Array<Route> | RouterGroup): RouterGroup | Array<RouterGroup>;
|
|
15
|
+
static connect(path: string, handler: string | HandlerType): Route;
|
|
16
|
+
static delete(path: string, handler: string | HandlerType): Route;
|
|
17
|
+
static get(path: string, handler: string | HandlerType): Route;
|
|
18
|
+
static head(path: string, handler: string | HandlerType): Route;
|
|
19
|
+
static options(path: string, handler: string | HandlerType): Route;
|
|
20
|
+
static patch(path: string, handler: string | HandlerType): Route;
|
|
21
|
+
static post(path: string, handler: string | HandlerType): Route;
|
|
22
|
+
static put(path: string, handler: string | HandlerType): Route;
|
|
23
|
+
static trace(path: string, handler: string | HandlerType): Route;
|
|
21
24
|
static match(methods: Array<HttpMethodEnum>, path: string, handler: string | HandlerType): RouterGroup;
|
|
22
25
|
static any(path: string, handler: string | HandlerType): RouterGroup;
|
|
26
|
+
static serialize(routes: Route | Array<Route> | RouterGroup | Array<RouterGroup>): RouterGroup;
|
|
23
27
|
}
|
package/facades/Router.js
CHANGED
|
@@ -12,16 +12,11 @@ export default class Router {
|
|
|
12
12
|
static x402() {
|
|
13
13
|
return new RouterBuilder().x402();
|
|
14
14
|
}
|
|
15
|
-
static
|
|
16
|
-
return new RouterBuilder().
|
|
15
|
+
static resource(path, controller, options) {
|
|
16
|
+
return new RouterBuilder().resource(path, controller, options);
|
|
17
17
|
}
|
|
18
|
-
static group(routes
|
|
19
|
-
|
|
20
|
-
if (prefix)
|
|
21
|
-
builder.prefix(prefix);
|
|
22
|
-
if (middlewares?.length)
|
|
23
|
-
builder.middleware(...middlewares);
|
|
24
|
-
return builder.group(routes);
|
|
18
|
+
static group(routes) {
|
|
19
|
+
return new RouterBuilder().group(routes);
|
|
25
20
|
}
|
|
26
21
|
static connect(path, handler) {
|
|
27
22
|
return new RouterBuilder().connect(path, handler);
|
|
@@ -56,4 +51,7 @@ export default class Router {
|
|
|
56
51
|
static any(path, handler) {
|
|
57
52
|
return new RouterBuilder().any(path, handler);
|
|
58
53
|
}
|
|
54
|
+
static serialize(routes) {
|
|
55
|
+
return new RouterBuilder().serialize(routes);
|
|
56
|
+
}
|
|
59
57
|
}
|
package/package.json
CHANGED
package/server.d.ts
CHANGED
package/server.js
CHANGED
|
@@ -1,50 +1,59 @@
|
|
|
1
1
|
import App from "@bejibun/app";
|
|
2
2
|
import Logger from "@bejibun/logger";
|
|
3
|
+
import { defineValue } from "@bejibun/utils";
|
|
3
4
|
import RuntimeException from "./exceptions/RuntimeException";
|
|
4
5
|
import Router from "./facades/Router";
|
|
5
6
|
import MaintenanceMiddleware from "./middlewares/MaintenanceMiddleware";
|
|
6
7
|
import RateLimiterMiddleware from "./middlewares/RateLimiterMiddleware";
|
|
7
8
|
import(App.Path.rootPath("bootstrap.ts"));
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
hmr: true,
|
|
36
|
-
// Echo console logs from the browser to the server
|
|
37
|
-
console: true
|
|
38
|
-
},
|
|
39
|
-
error: new ExceptionHandler().handle,
|
|
40
|
-
port: Bun.env.APP_PORT,
|
|
41
|
-
routes: {
|
|
42
|
-
"/": require(App.Path.publicPath("index.html")),
|
|
43
|
-
...Router.middleware(new MaintenanceMiddleware(), new RateLimiterMiddleware()).group([
|
|
44
|
-
Router.namespace("app/exceptions").any("/*", "Handler@route"),
|
|
45
|
-
ApiRoutes,
|
|
46
|
-
WebRoutes
|
|
47
|
-
])
|
|
9
|
+
export default class Server {
|
|
10
|
+
get exceptionHandler() {
|
|
11
|
+
const exceptionHandlerPath = App.Path.appPath("exceptions/handler.ts");
|
|
12
|
+
try {
|
|
13
|
+
return require(exceptionHandlerPath).default;
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
throw new RuntimeException(`Missing exception handler class [${exceptionHandlerPath}].`, null, error.message);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
get apiRoutes() {
|
|
20
|
+
const apiRoutesPath = App.Path.routesPath("api.ts");
|
|
21
|
+
try {
|
|
22
|
+
return require(apiRoutesPath).default;
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw new RuntimeException(`Missing api file on routes directory [${apiRoutesPath}].`, null, error.message);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
get webRoutes() {
|
|
29
|
+
const webRoutesPath = App.Path.routesPath("web.ts");
|
|
30
|
+
try {
|
|
31
|
+
return require(webRoutesPath).default;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new RuntimeException(`Missing web file on routes directory [${webRoutesPath}].`, null, error.message);
|
|
35
|
+
}
|
|
48
36
|
}
|
|
49
|
-
|
|
50
|
-
|
|
37
|
+
run() {
|
|
38
|
+
const server = Bun.serve({
|
|
39
|
+
development: Bun.env.NODE_ENV !== "production" && {
|
|
40
|
+
// Enable browser hot reloading in development
|
|
41
|
+
hmr: true,
|
|
42
|
+
// Echo console logs from the browser to the server
|
|
43
|
+
console: true
|
|
44
|
+
},
|
|
45
|
+
error: new this.exceptionHandler().handle,
|
|
46
|
+
port: Bun.env.APP_PORT,
|
|
47
|
+
routes: {
|
|
48
|
+
"/": require(App.Path.publicPath("index.html")),
|
|
49
|
+
...Object.assign({}, ...defineValue(Router.middleware(new MaintenanceMiddleware(), new RateLimiterMiddleware()).group([
|
|
50
|
+
Router.namespace("app/exceptions").any("/*", "Handler@route"),
|
|
51
|
+
Router.serialize(this.apiRoutes),
|
|
52
|
+
Router.serialize(this.webRoutes)
|
|
53
|
+
]), []))
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
Logger.setContext("APP").info(`🚀 Server running at ${server.url.origin}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
new Server().run();
|
package/types/router.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
import {IMiddleware} from "../types/middleware";
|
|
2
|
+
|
|
1
3
|
export type HandlerType = (request: Bun.BunRequest, server: Bun.Server) => Promise<Response>;
|
|
2
|
-
export type
|
|
4
|
+
export type RouterMethodMap = Record<string, HandlerType>;
|
|
5
|
+
export type RouterGroup = Record<string, RouterMethodMap | RouterGroup>;
|
|
6
|
+
export type RawRoute = {
|
|
7
|
+
prefix: string,
|
|
8
|
+
middlewares: Array<IMiddleware>,
|
|
9
|
+
namespace: string,
|
|
10
|
+
method: string,
|
|
11
|
+
path: string,
|
|
12
|
+
handler: string | HandlerType
|
|
13
|
+
};
|
|
14
|
+
export type Route = {
|
|
15
|
+
raw: RawRoute,
|
|
16
|
+
route: RouterGroup
|
|
17
|
+
};
|
|
3
18
|
export type ResourceAction = "index" | "store" | "show" | "update" | "destroy";
|