@bool-ts/core 1.7.17 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +1 -1
- package/__test/controller.ts +1 -1
- package/__test/index.ts +4 -1
- package/__test/module.ts +3 -1
- package/__test/tsconfig.json +109 -0
- package/__test/webSocket.ts +37 -0
- package/__test/webSocketClient.ts +23 -0
- package/dist/decorators/controller.d.ts +3 -3
- package/dist/decorators/controller.js +1 -2
- package/dist/decorators/dispatcher.d.ts +1 -1
- package/dist/decorators/http.d.ts +12 -12
- package/dist/decorators/http.js +1 -1
- package/dist/decorators/index.d.ts +5 -0
- package/dist/decorators/index.js +3 -0
- package/dist/decorators/module.d.ts +3 -1
- package/dist/decorators/module.js +9 -2
- package/dist/decorators/webSocket.d.ts +25 -0
- package/dist/decorators/webSocket.js +40 -0
- package/dist/decorators/webSocketArguments.d.ts +22 -0
- package/dist/decorators/webSocketArguments.js +49 -0
- package/dist/decorators/webSocketEvent.d.ts +15 -0
- package/dist/decorators/webSocketEvent.js +24 -0
- package/dist/decorators/zodSchema.js +3 -3
- package/dist/entities/{route.d.ts → httpRoute.d.ts} +12 -12
- package/dist/entities/{route.js → httpRoute.js} +27 -25
- package/dist/entities/httpRouter.d.ts +10 -0
- package/dist/entities/{router.js → httpRouter.js} +7 -5
- package/dist/entities/{routerGroup.d.ts → httpRouterGroup.d.ts} +4 -4
- package/dist/entities/{routerGroup.js → httpRouterGroup.js} +1 -1
- package/dist/entities/index.d.ts +7 -4
- package/dist/entities/index.js +6 -3
- package/dist/entities/webSocketRoute.d.ts +12 -0
- package/dist/entities/webSocketRoute.js +22 -0
- package/dist/entities/webSocketRouter.d.ts +31 -0
- package/dist/entities/webSocketRouter.js +54 -0
- package/dist/entities/webSocketRouterGroup.d.ts +25 -0
- package/dist/entities/webSocketRouterGroup.js +51 -0
- package/dist/hooks/factory.d.ts +0 -39
- package/dist/hooks/factory.js +398 -63
- package/dist/hooks/injector.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/webSocket.d.ts +2 -0
- package/dist/interfaces/webSocket.js +1 -0
- package/dist/keys/index.d.ts +10 -1
- package/dist/keys/index.js +21 -12
- package/dist/ultils/colors.d.ts +30 -0
- package/dist/ultils/colors.js +41 -0
- package/dist/ultils/index.d.ts +2 -0
- package/dist/ultils/index.js +2 -0
- package/dist/ultils/socket.d.ts +1 -0
- package/dist/ultils/socket.js +7 -0
- package/package.json +7 -7
- package/src/decorators/controller.ts +5 -4
- package/src/decorators/dispatcher.ts +2 -1
- package/src/decorators/guard.ts +1 -0
- package/src/decorators/http.ts +3 -3
- package/src/decorators/index.ts +10 -0
- package/src/decorators/middleware.ts +1 -0
- package/src/decorators/module.ts +14 -3
- package/src/decorators/webSocket.ts +81 -0
- package/src/decorators/webSocketArguments.ts +144 -0
- package/src/decorators/webSocketEvent.ts +56 -0
- package/src/decorators/zodSchema.ts +5 -3
- package/src/entities/{route.ts → httpRoute.ts} +71 -57
- package/src/entities/{router.ts → httpRouter.ts} +8 -6
- package/src/entities/{routerGroup.ts → httpRouterGroup.ts} +4 -4
- package/src/entities/index.ts +7 -4
- package/src/entities/webSocketRoute.ts +35 -0
- package/src/entities/webSocketRouter.ts +64 -0
- package/src/entities/webSocketRouterGroup.ts +64 -0
- package/src/hooks/factory.ts +622 -95
- package/src/hooks/injector.ts +2 -2
- package/src/index.ts +1 -1
- package/src/interfaces/index.ts +1 -0
- package/src/interfaces/webSocket.ts +1 -0
- package/src/keys/index.ts +22 -12
- package/src/ultils/colors.ts +56 -0
- package/src/ultils/index.ts +3 -1
- package/src/ultils/socket.ts +9 -0
- package/test.ts +0 -0
- package/tsconfig.json +3 -2
- package/dist/entities/router.d.ts +0 -10
package/dist/hooks/factory.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import "colors";
|
|
2
1
|
import "reflect-metadata";
|
|
3
2
|
import Qs from "qs";
|
|
4
3
|
import * as Zod from "zod";
|
|
5
4
|
import { ETimeUnit, add as TimeAdd } from "@bool-ts/date-time";
|
|
6
|
-
import {
|
|
5
|
+
import { HttpRouter, HttpRouterGroup, WebSocketRoute, WebSocketRouter, WebSocketRouterGroup } from "../entities";
|
|
7
6
|
import { HttpClientError, HttpServerError, jsonErrorInfer } from "../http";
|
|
8
|
-
import { argumentsKey, configKey, contextArgsKey, controllerHttpKey, controllerKey, moduleKey, paramArgsKey, paramsArgsKey, queryArgsKey, requestArgsKey, requestBodyArgsKey, requestHeaderArgsKey, requestHeadersArgsKey, responseBodyArgsKey, responseHeadersArgsKey, routeModelArgsKey } from "../keys";
|
|
7
|
+
import { argumentsKey, configKey, contextArgsKey, controllerHttpKey, controllerKey, moduleKey, paramArgsKey, paramsArgsKey, queryArgsKey, requestArgsKey, requestBodyArgsKey, requestHeaderArgsKey, requestHeadersArgsKey, responseBodyArgsKey, responseHeadersArgsKey, routeModelArgsKey, webSocketCloseCodeArgsKey, webSocketCloseReasonArgsKey, webSocketConnectionArgsKey, webSocketKey, webSocketMessageArgsKey, webSocketServerArgsKey } from "../keys";
|
|
8
|
+
import { ansiText, isWebSocketUpgrade } from "../ultils";
|
|
9
9
|
import { Injector } from "./injector";
|
|
10
10
|
const DEFAULT_STATIC_CACHE_TIME_IN_SECONDS = 900;
|
|
11
|
-
|
|
11
|
+
const responseConverter = (response) => {
|
|
12
12
|
response.headers.set("X-Powered-By", "Bool Typescript");
|
|
13
13
|
return response;
|
|
14
14
|
};
|
|
15
|
-
|
|
15
|
+
const controllerCreator = ({ controllerConstructor, httpRouterGroup, injector, prefix }) => {
|
|
16
16
|
if (!Reflect.getOwnMetadataKeys(controllerConstructor).includes(controllerKey)) {
|
|
17
17
|
throw Error(`${controllerConstructor.name} is not a controller.`);
|
|
18
18
|
}
|
|
@@ -24,8 +24,9 @@ export const controllerCreator = (controllerConstructor, group, injector, prefix
|
|
|
24
24
|
prefix: "/",
|
|
25
25
|
httpMetadata: []
|
|
26
26
|
};
|
|
27
|
-
const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) ||
|
|
28
|
-
|
|
27
|
+
const routesMetadata = (Reflect.getOwnMetadata(controllerHttpKey, controllerConstructor) ||
|
|
28
|
+
[]);
|
|
29
|
+
const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
|
|
29
30
|
routesMetadata.forEach((routeMetadata) => {
|
|
30
31
|
if (typeof routeMetadata.descriptor.value !== "function") {
|
|
31
32
|
return;
|
|
@@ -52,9 +53,64 @@ export const controllerCreator = (controllerConstructor, group, injector, prefix
|
|
|
52
53
|
return route.options(routeArgument);
|
|
53
54
|
}
|
|
54
55
|
});
|
|
55
|
-
return
|
|
56
|
+
return httpRouterGroup.add(router);
|
|
56
57
|
};
|
|
57
|
-
|
|
58
|
+
const webSocketCreator = ({ injector, httpRouterGroup, prefix, webSocketRouterGroup, webSocketConstructor }) => {
|
|
59
|
+
if (!Reflect.getOwnMetadataKeys(webSocketConstructor).includes(webSocketKey)) {
|
|
60
|
+
throw Error(`${webSocketConstructor.name} is not a controller.`);
|
|
61
|
+
}
|
|
62
|
+
const webSocket = injector.get(webSocketConstructor);
|
|
63
|
+
if (!webSocket) {
|
|
64
|
+
throw Error("Can not initialize webSocket.");
|
|
65
|
+
}
|
|
66
|
+
const webSocketMetadata = Reflect.getOwnMetadata(webSocketKey, webSocketConstructor) || {
|
|
67
|
+
prefix: "/",
|
|
68
|
+
events: [],
|
|
69
|
+
http: []
|
|
70
|
+
};
|
|
71
|
+
const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
|
|
72
|
+
//#region [HTTP ROUTER]
|
|
73
|
+
const router = new HttpRouter(fullPrefix);
|
|
74
|
+
for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
|
|
75
|
+
if (typeof httpMetadata.descriptor?.value !== "function") {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const route = router.route(httpMetadata.path);
|
|
79
|
+
const handler = httpMetadata.descriptor.value.bind(webSocket);
|
|
80
|
+
const routeArgument = Object.freeze({
|
|
81
|
+
class: webSocketConstructor,
|
|
82
|
+
funcName: httpMetadata.methodName,
|
|
83
|
+
func: handler
|
|
84
|
+
});
|
|
85
|
+
switch (httpMetadata.httpMethod) {
|
|
86
|
+
case "GET":
|
|
87
|
+
route.get(routeArgument);
|
|
88
|
+
break;
|
|
89
|
+
case "POST":
|
|
90
|
+
route.post(routeArgument);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
httpRouterGroup.add(router);
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region [WEBSOCKET ROUTER]
|
|
97
|
+
const webSocketRouter = new WebSocketRouter(fullPrefix);
|
|
98
|
+
for (const [key, event] of Object.entries(webSocketMetadata.events)) {
|
|
99
|
+
const webSocketRoute = new WebSocketRoute({
|
|
100
|
+
eventName: key,
|
|
101
|
+
metadata: event
|
|
102
|
+
});
|
|
103
|
+
webSocketRouter.addRoutes(webSocketRoute);
|
|
104
|
+
}
|
|
105
|
+
webSocketRouter.bind(webSocket);
|
|
106
|
+
webSocketRouterGroup.addRouters(webSocketRouter);
|
|
107
|
+
//#endregion
|
|
108
|
+
return Object.freeze({
|
|
109
|
+
httpRouterGroup: httpRouterGroup,
|
|
110
|
+
webSocketRouterGroup: webSocketRouterGroup
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const argumentsResolution = async (data, zodSchema, argumentIndex, funcName) => {
|
|
58
114
|
try {
|
|
59
115
|
const validation = await zodSchema.safeParseAsync(data);
|
|
60
116
|
if (!validation.success) {
|
|
@@ -85,7 +141,7 @@ export const argumentsResolution = async (data, zodSchema, argumentIndex, funcNa
|
|
|
85
141
|
});
|
|
86
142
|
}
|
|
87
143
|
};
|
|
88
|
-
|
|
144
|
+
const moduleResolution = async (module, options) => {
|
|
89
145
|
if (!Reflect.getOwnMetadataKeys(module).includes(moduleKey)) {
|
|
90
146
|
throw Error(`${module.name} is not a module.`);
|
|
91
147
|
}
|
|
@@ -94,8 +150,9 @@ export const moduleResolution = async (module, options) => {
|
|
|
94
150
|
if (!moduleMetadata) {
|
|
95
151
|
return;
|
|
96
152
|
}
|
|
97
|
-
const { loaders, middlewares, guards, dispatchers, controllers, dependencies, prefix: modulePrefix, config: moduleConfig } = moduleMetadata;
|
|
98
|
-
|
|
153
|
+
const { loaders, middlewares, guards, dispatchers, controllers, dependencies, webSockets, prefix: modulePrefix, config: moduleConfig } = moduleMetadata;
|
|
154
|
+
const fullPrefix = `${options.prefix || ""}/${modulePrefix || ""}`;
|
|
155
|
+
//#region [Configuration(s)]
|
|
99
156
|
const { config } = Object.freeze({
|
|
100
157
|
config: {
|
|
101
158
|
...(typeof options.config !== "function" ? options.config : await options.config()),
|
|
@@ -106,19 +163,30 @@ export const moduleResolution = async (module, options) => {
|
|
|
106
163
|
: await moduleConfig())
|
|
107
164
|
}
|
|
108
165
|
});
|
|
109
|
-
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region [Register config like an injection]
|
|
110
168
|
injector.set(configKey, config);
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region [Run loader(s)]
|
|
111
171
|
if (loaders) {
|
|
112
172
|
const loaderFunctions = [];
|
|
113
173
|
for (const [key, func] of Object.entries(loaders)) {
|
|
114
174
|
loaderFunctions.push(async () => {
|
|
115
175
|
try {
|
|
116
176
|
const result = await func({ config });
|
|
117
|
-
console.info(
|
|
177
|
+
console.info(`${ansiText(" INFO ", {
|
|
178
|
+
color: "white",
|
|
179
|
+
backgroundColor: "blue",
|
|
180
|
+
bold: true
|
|
181
|
+
})} Loader [${key}] initialized successfully.`);
|
|
118
182
|
return result;
|
|
119
183
|
}
|
|
120
184
|
catch (error) {
|
|
121
|
-
console.error(
|
|
185
|
+
console.error(`${ansiText(" WARN ", {
|
|
186
|
+
color: "yellow",
|
|
187
|
+
backgroundColor: "red",
|
|
188
|
+
bold: true
|
|
189
|
+
})} Loader [${key}] initialization failed.`);
|
|
122
190
|
options.debug && console.error(error);
|
|
123
191
|
throw error;
|
|
124
192
|
}
|
|
@@ -130,31 +198,33 @@ export const moduleResolution = async (module, options) => {
|
|
|
130
198
|
injector.set(key, value);
|
|
131
199
|
}
|
|
132
200
|
}
|
|
133
|
-
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region [Dependencies]
|
|
134
203
|
!dependencies || dependencies.map((dependency) => injector.get(dependency));
|
|
135
|
-
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region [Middleware(s)]
|
|
136
206
|
const startMiddlewareGroup = [];
|
|
137
207
|
const endMiddlewareGroup = [];
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const instance = injector.get(
|
|
208
|
+
middlewares &&
|
|
209
|
+
middlewares.forEach((middleware) => {
|
|
210
|
+
const instance = injector.get(middleware);
|
|
141
211
|
if (instance.start && typeof instance.start === "function") {
|
|
142
212
|
startMiddlewareGroup.push(Object.freeze({
|
|
143
|
-
class:
|
|
213
|
+
class: middleware,
|
|
144
214
|
funcName: "start",
|
|
145
215
|
func: instance.start.bind(instance)
|
|
146
216
|
}));
|
|
147
217
|
}
|
|
148
218
|
if (instance.end && typeof instance.end === "function") {
|
|
149
219
|
endMiddlewareGroup.push(Object.freeze({
|
|
150
|
-
class:
|
|
220
|
+
class: middleware,
|
|
151
221
|
funcName: "end",
|
|
152
222
|
func: instance.end.bind(instance)
|
|
153
223
|
}));
|
|
154
224
|
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
225
|
+
});
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region [Guard(s)]
|
|
158
228
|
const guardGroup = !guards
|
|
159
229
|
? []
|
|
160
230
|
: guards.map((guard) => {
|
|
@@ -165,32 +235,51 @@ export const moduleResolution = async (module, options) => {
|
|
|
165
235
|
func: guardInstance.enforce.bind(guardInstance)
|
|
166
236
|
});
|
|
167
237
|
});
|
|
168
|
-
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region [Before dispatcher(s)]
|
|
169
240
|
const openDispatcherGroup = [];
|
|
170
241
|
const closeDispatcherGroup = [];
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const instance = injector.get(
|
|
242
|
+
dispatchers &&
|
|
243
|
+
dispatchers.forEach((dispatcher) => {
|
|
244
|
+
const instance = injector.get(dispatcher);
|
|
174
245
|
if (instance.open && typeof instance.open === "function") {
|
|
175
246
|
openDispatcherGroup.push(Object.freeze({
|
|
176
|
-
class:
|
|
247
|
+
class: dispatcher,
|
|
177
248
|
funcName: "open",
|
|
178
249
|
func: instance.open.bind(instance)
|
|
179
250
|
}));
|
|
180
251
|
}
|
|
181
252
|
if (instance.close && typeof instance.close === "function") {
|
|
182
253
|
closeDispatcherGroup.push(Object.freeze({
|
|
183
|
-
class:
|
|
254
|
+
class: dispatcher,
|
|
184
255
|
funcName: "close",
|
|
185
256
|
func: instance.close.bind(instance)
|
|
186
257
|
}));
|
|
187
258
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
259
|
+
});
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region [Controller(s)]
|
|
262
|
+
const controllerRouterGroup = new HttpRouterGroup();
|
|
192
263
|
controllers &&
|
|
193
|
-
controllers.
|
|
264
|
+
controllers.forEach((controllerConstructor) => controllerCreator({
|
|
265
|
+
controllerConstructor,
|
|
266
|
+
httpRouterGroup: controllerRouterGroup,
|
|
267
|
+
injector: injector,
|
|
268
|
+
prefix: fullPrefix
|
|
269
|
+
}));
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region [WebSocket(s)]
|
|
272
|
+
const webSocketHttpRouterGroup = new HttpRouterGroup();
|
|
273
|
+
const webSocketRouterGroup = new WebSocketRouterGroup();
|
|
274
|
+
webSockets &&
|
|
275
|
+
webSockets.forEach((webSocket) => webSocketCreator({
|
|
276
|
+
webSocketConstructor: webSocket,
|
|
277
|
+
httpRouterGroup: webSocketHttpRouterGroup,
|
|
278
|
+
webSocketRouterGroup: webSocketRouterGroup,
|
|
279
|
+
injector,
|
|
280
|
+
prefix: fullPrefix
|
|
281
|
+
}));
|
|
282
|
+
//#endregion
|
|
194
283
|
return Object.freeze({
|
|
195
284
|
prefix: moduleMetadata.prefix,
|
|
196
285
|
injector: injector,
|
|
@@ -199,12 +288,43 @@ export const moduleResolution = async (module, options) => {
|
|
|
199
288
|
guardGroup,
|
|
200
289
|
openDispatcherGroup,
|
|
201
290
|
closeDispatcherGroup,
|
|
202
|
-
|
|
291
|
+
controllerRouterGroup,
|
|
292
|
+
webSocketHttpRouterGroup,
|
|
293
|
+
webSocketRouterGroup
|
|
203
294
|
});
|
|
204
295
|
};
|
|
205
|
-
const
|
|
206
|
-
const {
|
|
296
|
+
const webSocketFetcher = async (bun, bool) => {
|
|
297
|
+
const { request, server } = bun;
|
|
298
|
+
const { query, responseHeaders, route: { model } } = bool;
|
|
299
|
+
// Execute controller action
|
|
300
|
+
const isUpgrade = await model.func(...[server, request, query]);
|
|
301
|
+
if (typeof isUpgrade !== "boolean") {
|
|
302
|
+
return responseConverter(new Response(JSON.stringify({
|
|
303
|
+
httpCode: 500,
|
|
304
|
+
message: "Can not detect webSocket upgrade result.",
|
|
305
|
+
data: undefined
|
|
306
|
+
}), {
|
|
307
|
+
status: 500,
|
|
308
|
+
statusText: "Internal server error.",
|
|
309
|
+
headers: responseHeaders
|
|
310
|
+
}));
|
|
311
|
+
}
|
|
312
|
+
if (!isUpgrade) {
|
|
313
|
+
return responseConverter(new Response(JSON.stringify({
|
|
314
|
+
httpCode: 500,
|
|
315
|
+
message: "Can not upgrade.",
|
|
316
|
+
data: undefined
|
|
317
|
+
}), {
|
|
318
|
+
status: 500,
|
|
319
|
+
statusText: "Internal server error.",
|
|
320
|
+
headers: responseHeaders
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
return isUpgrade;
|
|
324
|
+
};
|
|
325
|
+
const httpFetcher = async (bun, bool) => {
|
|
207
326
|
const { request, server: _server } = bun;
|
|
327
|
+
const { query, responseHeaders, route: { parameters, model }, moduleResolution: { startMiddlewareGroup, endMiddlewareGroup, guardGroup, openDispatcherGroup, closeDispatcherGroup } } = bool;
|
|
208
328
|
const context = {
|
|
209
329
|
[requestHeadersArgsKey]: request.headers,
|
|
210
330
|
[responseHeadersArgsKey]: responseHeaders,
|
|
@@ -242,7 +362,9 @@ const fetcher = async (bun, bool) => {
|
|
|
242
362
|
: await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
243
363
|
break;
|
|
244
364
|
case contextArgsKey:
|
|
245
|
-
args[argsMetadata.index] = !argsMetadata.key
|
|
365
|
+
args[argsMetadata.index] = !argsMetadata.key
|
|
366
|
+
? contextHook
|
|
367
|
+
: contextHook.get(argsMetadata.key);
|
|
246
368
|
break;
|
|
247
369
|
case requestHeadersArgsKey:
|
|
248
370
|
args[argsMetadata.index] = !argsMetadata.zodSchema
|
|
@@ -270,7 +392,9 @@ const fetcher = async (bun, bool) => {
|
|
|
270
392
|
? !(argsMetadata.type in context)
|
|
271
393
|
? undefined
|
|
272
394
|
: context[argsMetadata.type]
|
|
273
|
-
: await argumentsResolution(!(argsMetadata.type in context)
|
|
395
|
+
: await argumentsResolution(!(argsMetadata.type in context)
|
|
396
|
+
? undefined
|
|
397
|
+
: context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
274
398
|
break;
|
|
275
399
|
}
|
|
276
400
|
}
|
|
@@ -299,7 +423,9 @@ const fetcher = async (bun, bool) => {
|
|
|
299
423
|
: await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
300
424
|
break;
|
|
301
425
|
case contextArgsKey:
|
|
302
|
-
args[argsMetadata.index] = !argsMetadata.key
|
|
426
|
+
args[argsMetadata.index] = !argsMetadata.key
|
|
427
|
+
? contextHook
|
|
428
|
+
: contextHook.get(argsMetadata.key);
|
|
303
429
|
break;
|
|
304
430
|
case requestHeadersArgsKey:
|
|
305
431
|
args[argsMetadata.index] = !argsMetadata.zodSchema
|
|
@@ -358,7 +484,9 @@ const fetcher = async (bun, bool) => {
|
|
|
358
484
|
: await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
359
485
|
break;
|
|
360
486
|
case contextArgsKey:
|
|
361
|
-
args[argsMetadata.index] = !argsMetadata.key
|
|
487
|
+
args[argsMetadata.index] = !argsMetadata.key
|
|
488
|
+
? contextHook
|
|
489
|
+
: contextHook.get(argsMetadata.key);
|
|
362
490
|
break;
|
|
363
491
|
case requestHeadersArgsKey:
|
|
364
492
|
args[argsMetadata.index] = !argsMetadata.zodSchema
|
|
@@ -462,7 +590,9 @@ const fetcher = async (bun, bool) => {
|
|
|
462
590
|
: await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
463
591
|
break;
|
|
464
592
|
case contextArgsKey:
|
|
465
|
-
args[argsMetadata.index] = !argsMetadata.key
|
|
593
|
+
args[argsMetadata.index] = !argsMetadata.key
|
|
594
|
+
? contextHook
|
|
595
|
+
: contextHook.get(argsMetadata.key);
|
|
466
596
|
break;
|
|
467
597
|
case requestHeadersArgsKey:
|
|
468
598
|
args[argsMetadata.index] = !argsMetadata.zodSchema
|
|
@@ -517,7 +647,9 @@ const fetcher = async (bun, bool) => {
|
|
|
517
647
|
: await argumentsResolution(await request[argsMetadata.parser || "json"](), argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
518
648
|
break;
|
|
519
649
|
case contextArgsKey:
|
|
520
|
-
args[argsMetadata.index] = !argsMetadata.key
|
|
650
|
+
args[argsMetadata.index] = !argsMetadata.key
|
|
651
|
+
? contextHook
|
|
652
|
+
: contextHook.get(argsMetadata.key);
|
|
521
653
|
break;
|
|
522
654
|
case requestHeadersArgsKey:
|
|
523
655
|
args[argsMetadata.index] = !argsMetadata.zodSchema
|
|
@@ -545,7 +677,9 @@ const fetcher = async (bun, bool) => {
|
|
|
545
677
|
? !(argsMetadata.type in context)
|
|
546
678
|
? undefined
|
|
547
679
|
: context[argsMetadata.type]
|
|
548
|
-
: await argumentsResolution(!(argsMetadata.type in context)
|
|
680
|
+
: await argumentsResolution(!(argsMetadata.type in context)
|
|
681
|
+
? undefined
|
|
682
|
+
: context[argsMetadata.type], argsMetadata.zodSchema, argsMetadata.index, collection.funcName);
|
|
549
683
|
break;
|
|
550
684
|
}
|
|
551
685
|
}
|
|
@@ -581,9 +715,18 @@ export const BoolFactory = async (modules, options) => {
|
|
|
581
715
|
? ["*"]
|
|
582
716
|
: options.cors.origins
|
|
583
717
|
: [options.cors.origins !== "*" ? options.cors.origins : "*"],
|
|
584
|
-
allowMethods: options.cors?.methods || [
|
|
718
|
+
allowMethods: options.cors?.methods || [
|
|
719
|
+
"GET",
|
|
720
|
+
"POST",
|
|
721
|
+
"PUT",
|
|
722
|
+
"PATCH",
|
|
723
|
+
"DELETE",
|
|
724
|
+
"OPTIONS"
|
|
725
|
+
],
|
|
585
726
|
allowCredentials: !options.cors?.credentials ? false : true,
|
|
586
|
-
allowHeaders: !options.cors?.headers || options.cors.headers.includes("*")
|
|
727
|
+
allowHeaders: !options.cors?.headers || options.cors.headers.includes("*")
|
|
728
|
+
? ["*"]
|
|
729
|
+
: options.cors.headers
|
|
587
730
|
});
|
|
588
731
|
const moduleResolutions = await Promise.all(modulesConverted.map((moduleConverted) => moduleResolution(moduleConverted, options)));
|
|
589
732
|
const availableModuleResolutions = moduleResolutions.filter((moduleResolution) => typeof moduleResolution !== "undefined");
|
|
@@ -591,9 +734,16 @@ export const BoolFactory = async (modules, options) => {
|
|
|
591
734
|
...new Set(availableModuleResolutions.map((availableModuleResolution) => availableModuleResolution.prefix))
|
|
592
735
|
];
|
|
593
736
|
if (prefixs.length !== availableModuleResolutions.length) {
|
|
594
|
-
throw Error(
|
|
737
|
+
throw Error("Module prefix should be unique.");
|
|
738
|
+
}
|
|
739
|
+
const webSocketsMap = new Map();
|
|
740
|
+
for (const availableModuleResolution of availableModuleResolutions) {
|
|
741
|
+
const webSocketMap = availableModuleResolution.webSocketRouterGroup.execute();
|
|
742
|
+
for (const [key, metadata] of webSocketMap.entries()) {
|
|
743
|
+
webSocketsMap.set(key, metadata);
|
|
744
|
+
}
|
|
595
745
|
}
|
|
596
|
-
Bun.serve({
|
|
746
|
+
const server = Bun.serve({
|
|
597
747
|
port: options.port,
|
|
598
748
|
fetch: async (request, server) => {
|
|
599
749
|
const start = performance.now();
|
|
@@ -603,10 +753,50 @@ export const BoolFactory = async (modules, options) => {
|
|
|
603
753
|
const method = request.method.toUpperCase();
|
|
604
754
|
const responseHeaders = new Headers();
|
|
605
755
|
try {
|
|
606
|
-
|
|
756
|
+
const isUpgradable = isWebSocketUpgrade(request);
|
|
757
|
+
let collection;
|
|
758
|
+
if (isUpgradable) {
|
|
759
|
+
for (const availableModuleResolution of availableModuleResolutions) {
|
|
760
|
+
const routeResult = availableModuleResolution.webSocketHttpRouterGroup.find(url.pathname, request.method);
|
|
761
|
+
if (routeResult) {
|
|
762
|
+
collection = Object.freeze({
|
|
763
|
+
route: routeResult,
|
|
764
|
+
resolution: availableModuleResolution
|
|
765
|
+
});
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (!collection) {
|
|
770
|
+
return responseConverter(new Response(JSON.stringify({
|
|
771
|
+
httpCode: 404,
|
|
772
|
+
message: "Route not found",
|
|
773
|
+
data: undefined
|
|
774
|
+
}), {
|
|
775
|
+
status: 404,
|
|
776
|
+
statusText: "Not found.",
|
|
777
|
+
headers: responseHeaders
|
|
778
|
+
}));
|
|
779
|
+
}
|
|
780
|
+
const upgradeResult = await webSocketFetcher({
|
|
781
|
+
request,
|
|
782
|
+
server
|
|
783
|
+
}, {
|
|
784
|
+
query: query,
|
|
785
|
+
responseHeaders: responseHeaders,
|
|
786
|
+
route: collection.route,
|
|
787
|
+
moduleResolution: collection.resolution
|
|
788
|
+
});
|
|
789
|
+
return upgradeResult instanceof Response ? upgradeResult : undefined;
|
|
790
|
+
}
|
|
791
|
+
allowCredentials &&
|
|
792
|
+
responseHeaders.set("Access-Control-Allow-Credentials", "true");
|
|
607
793
|
responseHeaders.set("Access-Control-Allow-Methods", allowMethods.join(", "));
|
|
608
794
|
responseHeaders.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
|
|
609
|
-
responseHeaders.set("Access-Control-Allow-Origin", allowOrigins.includes("*")
|
|
795
|
+
responseHeaders.set("Access-Control-Allow-Origin", allowOrigins.includes("*")
|
|
796
|
+
? "*"
|
|
797
|
+
: !allowOrigins.includes(origin)
|
|
798
|
+
? allowOrigins[0]
|
|
799
|
+
: origin);
|
|
610
800
|
if (!allowMethods.includes(method)) {
|
|
611
801
|
return responseConverter(new Response(undefined, {
|
|
612
802
|
status: 405,
|
|
@@ -676,13 +866,12 @@ export const BoolFactory = async (modules, options) => {
|
|
|
676
866
|
}
|
|
677
867
|
}
|
|
678
868
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
const routeResult = availableModuleResolutions[i].routerGroup.find(url.pathname, request.method);
|
|
869
|
+
for (const availableModuleResolution of availableModuleResolutions) {
|
|
870
|
+
const routeResult = availableModuleResolution.controllerRouterGroup.find(url.pathname, request.method);
|
|
682
871
|
if (routeResult) {
|
|
683
872
|
collection = Object.freeze({
|
|
684
873
|
route: routeResult,
|
|
685
|
-
resolution:
|
|
874
|
+
resolution: availableModuleResolution
|
|
686
875
|
});
|
|
687
876
|
break;
|
|
688
877
|
}
|
|
@@ -698,7 +887,7 @@ export const BoolFactory = async (modules, options) => {
|
|
|
698
887
|
headers: responseHeaders
|
|
699
888
|
}));
|
|
700
889
|
}
|
|
701
|
-
return await
|
|
890
|
+
return await httpFetcher({
|
|
702
891
|
request,
|
|
703
892
|
server
|
|
704
893
|
}, {
|
|
@@ -715,16 +904,162 @@ export const BoolFactory = async (modules, options) => {
|
|
|
715
904
|
finally {
|
|
716
905
|
if (allowLogsMethods) {
|
|
717
906
|
const end = performance.now();
|
|
718
|
-
const
|
|
719
|
-
const
|
|
720
|
-
const
|
|
907
|
+
const pathname = ansiText(url.pathname, { color: "blue" });
|
|
908
|
+
const convertedPID = `${Bun.color("yellow", "ansi")}${process.pid}`;
|
|
909
|
+
const convertedMethod = ansiText(request.method, {
|
|
910
|
+
color: "yellow",
|
|
911
|
+
backgroundColor: "blue"
|
|
912
|
+
});
|
|
913
|
+
const convertedReqIp = ansiText(`${request.headers.get("x-forwarded-for") ||
|
|
721
914
|
request.headers.get("x-real-ip") ||
|
|
722
915
|
server.requestIP(request)?.address ||
|
|
723
|
-
"<Unknown>"}
|
|
724
|
-
|
|
916
|
+
"<Unknown>"}`, {
|
|
917
|
+
color: "yellow"
|
|
918
|
+
});
|
|
919
|
+
const convertedTime = ansiText(`${Math.round((end - start + Number.EPSILON) * 10 ** 2) / 10 ** 2}ms`, {
|
|
920
|
+
color: "yellow",
|
|
921
|
+
backgroundColor: "blue"
|
|
922
|
+
});
|
|
725
923
|
allowLogsMethods.includes(request.method.toUpperCase()) &&
|
|
726
|
-
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${
|
|
924
|
+
console.info(`PID: ${convertedPID} - Method: ${convertedMethod} - IP: ${convertedReqIp} - ${pathname} - Time: ${convertedTime}`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
websocket: {
|
|
929
|
+
open: (connection) => {
|
|
930
|
+
const pathnameKey = `${connection.data.pathname}:::open`;
|
|
931
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
932
|
+
if (!handlerMetadata) {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
936
|
+
const args = [];
|
|
937
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
938
|
+
switch (argumentMetadata.type) {
|
|
939
|
+
case webSocketConnectionArgsKey:
|
|
940
|
+
args[argumentMetadata.index] = connection;
|
|
941
|
+
break;
|
|
942
|
+
case webSocketServerArgsKey:
|
|
943
|
+
args[argumentMetadata.index] = server;
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
handlerMetadata.descriptor.value(...args);
|
|
948
|
+
},
|
|
949
|
+
close: (connection, code, reason) => {
|
|
950
|
+
const pathnameKey = `${connection.data.pathname}:::close`;
|
|
951
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
952
|
+
if (!handlerMetadata) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
956
|
+
const args = [];
|
|
957
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
958
|
+
switch (argumentMetadata.type) {
|
|
959
|
+
case webSocketConnectionArgsKey:
|
|
960
|
+
args[argumentMetadata.index] = connection;
|
|
961
|
+
break;
|
|
962
|
+
case webSocketServerArgsKey:
|
|
963
|
+
args[argumentMetadata.index] = server;
|
|
964
|
+
break;
|
|
965
|
+
case webSocketCloseCodeArgsKey:
|
|
966
|
+
args[argumentMetadata.index] = code;
|
|
967
|
+
break;
|
|
968
|
+
case webSocketCloseReasonArgsKey:
|
|
969
|
+
args[argumentMetadata.index] = reason;
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
handlerMetadata.descriptor.value(...args);
|
|
974
|
+
},
|
|
975
|
+
message: (connection, message) => {
|
|
976
|
+
const pathnameKey = `${connection.data.pathname}:::message`;
|
|
977
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
978
|
+
if (!handlerMetadata) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
982
|
+
const args = [];
|
|
983
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
984
|
+
switch (argumentMetadata.type) {
|
|
985
|
+
case webSocketConnectionArgsKey:
|
|
986
|
+
args[argumentMetadata.index] = connection;
|
|
987
|
+
break;
|
|
988
|
+
case webSocketMessageArgsKey:
|
|
989
|
+
args[argumentMetadata.index] = message;
|
|
990
|
+
break;
|
|
991
|
+
case webSocketServerArgsKey:
|
|
992
|
+
args[argumentMetadata.index] = server;
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
handlerMetadata.descriptor.value(...args);
|
|
997
|
+
},
|
|
998
|
+
drain: (connection) => {
|
|
999
|
+
const pathnameKey = `${connection.data.pathname}:::drain`;
|
|
1000
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
1001
|
+
if (!handlerMetadata) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
1005
|
+
const args = [];
|
|
1006
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
1007
|
+
switch (argumentMetadata.type) {
|
|
1008
|
+
case webSocketConnectionArgsKey:
|
|
1009
|
+
args[argumentMetadata.index] = connection;
|
|
1010
|
+
break;
|
|
1011
|
+
case webSocketServerArgsKey:
|
|
1012
|
+
args[argumentMetadata.index] = server;
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
handlerMetadata.descriptor.value(...args);
|
|
1017
|
+
},
|
|
1018
|
+
ping: (connection, data) => {
|
|
1019
|
+
const pathnameKey = `${connection.data.pathname}:::ping`;
|
|
1020
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
1021
|
+
if (!handlerMetadata) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
1025
|
+
const args = [];
|
|
1026
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
1027
|
+
switch (argumentMetadata.type) {
|
|
1028
|
+
case webSocketConnectionArgsKey:
|
|
1029
|
+
args[argumentMetadata.index] = connection;
|
|
1030
|
+
break;
|
|
1031
|
+
case webSocketServerArgsKey:
|
|
1032
|
+
args[argumentMetadata.index] = server;
|
|
1033
|
+
break;
|
|
1034
|
+
case webSocketMessageArgsKey:
|
|
1035
|
+
args[argumentMetadata.index] = data;
|
|
1036
|
+
break;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
handlerMetadata.descriptor.value(...args);
|
|
1040
|
+
},
|
|
1041
|
+
pong: (connection, data) => {
|
|
1042
|
+
const pathnameKey = `${connection.data.pathname}:::pong`;
|
|
1043
|
+
const handlerMetadata = webSocketsMap.get(pathnameKey);
|
|
1044
|
+
if (!handlerMetadata) {
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
const argumentsMetadata = handlerMetadata.arguments || {};
|
|
1048
|
+
const args = [];
|
|
1049
|
+
for (const [_key, argumentMetadata] of Object.entries(argumentsMetadata)) {
|
|
1050
|
+
switch (argumentMetadata.type) {
|
|
1051
|
+
case webSocketConnectionArgsKey:
|
|
1052
|
+
args[argumentMetadata.index] = connection;
|
|
1053
|
+
break;
|
|
1054
|
+
case webSocketServerArgsKey:
|
|
1055
|
+
args[argumentMetadata.index] = server;
|
|
1056
|
+
break;
|
|
1057
|
+
case webSocketMessageArgsKey:
|
|
1058
|
+
args[argumentMetadata.index] = data;
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
727
1061
|
}
|
|
1062
|
+
handlerMetadata.descriptor.value(...args);
|
|
728
1063
|
}
|
|
729
1064
|
}
|
|
730
1065
|
});
|