@bool-ts/core 2.1.3 → 2.2.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/package.json CHANGED
@@ -43,5 +43,5 @@
43
43
  "test": "bun --hot run __test/index.ts"
44
44
  },
45
45
  "types": "./dist/index.d.ts",
46
- "version": "2.1.3"
46
+ "version": "2.2.0"
47
47
  }
@@ -7,13 +7,20 @@ import type {
7
7
  TWebSocketEventHandlerMetadata,
8
8
  TWebSocketMetadata
9
9
  } from "../decorators";
10
- import { HttpClientError, HttpServerError, jsonErrorInfer, type THttpMethods } from "../http";
10
+ import type { THttpMethods } from "../http";
11
11
  import type { IGuard, IInterceptor, IMiddleware } from "../interfaces";
12
+ import type { ICustomValidator } from "../interfaces/customValidator";
12
13
  import type { TConstructor } from "../ultils";
13
14
 
14
15
  import { ETimeUnit, add as TimeAdd } from "@bool-ts/date-time";
15
16
  import { parse as QsParse } from "qs";
16
- import type { ICustomValidator } from "../interfaces/customValidator";
17
+ import {
18
+ HttpClientError,
19
+ httpMethods,
20
+ httpMethodsStandardization,
21
+ HttpServerError,
22
+ jsonErrorInfer
23
+ } from "../http";
17
24
  import {
18
25
  argumentsKey,
19
26
  configKey,
@@ -46,38 +53,39 @@ import { Context } from "./context";
46
53
  import { HttpRouter } from "./httpRouter";
47
54
  import { HttpRouterGroup } from "./httpRouterGroup";
48
55
  import { Injector } from "./injector";
49
- import ValidationFailed from "./validationFailed";
56
+ import { ValidationFailed } from "./validationFailed";
50
57
  import { WebSocketRoute } from "./webSocketRoute";
51
58
  import { WebSocketRouter } from "./webSocketRouter";
52
59
  import { WebSocketRouterGroup } from "./webSocketRouterGroup";
53
60
 
54
61
  type TParamsType = Record<string, string>;
55
62
 
56
- type TApplicationOptions = Required<{
57
- port: number;
58
- }> &
59
- Partial<{
60
- config: Record<string | symbol, any> | (() => Record<string | symbol, any>);
61
- prefix: string;
62
- debug: boolean;
63
- log: Partial<{
64
- methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
65
- }>;
66
- queryParser: Parameters<typeof QsParse>[1];
67
- static: Required<{
68
- path: string;
69
- }> &
70
- Partial<{
71
- headers: TParamsType;
72
- cacheTimeInSeconds: number;
63
+ type TApplicationOptions<AllowedMethods extends Array<THttpMethods> = Array<THttpMethods>> =
64
+ Required<{
65
+ port: number;
66
+ }> &
67
+ Partial<{
68
+ config: Record<string | symbol, any> | (() => Record<string | symbol, any>);
69
+ prefix: string;
70
+ debug: boolean;
71
+ log: Partial<{
72
+ methods: AllowedMethods;
73
+ }>;
74
+ queryParser: Parameters<typeof QsParse>[1];
75
+ static: Required<{
76
+ path: string;
77
+ }> &
78
+ Partial<{
79
+ headers: TParamsType;
80
+ cacheTimeInSeconds: number;
81
+ }>;
82
+ cors: Partial<{
83
+ credentials: boolean;
84
+ origins: string | Array<string>;
85
+ methods: Array<THttpMethods>;
86
+ headers: Array<string>;
73
87
  }>;
74
- cors: Partial<{
75
- credentials: boolean;
76
- origins: string | Array<string>;
77
- methods: Array<"GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS">;
78
- headers: Array<string>;
79
88
  }>;
80
- }>;
81
89
 
82
90
  type TGroupElementModel<
83
91
  TFuncName extends keyof TClass,
@@ -99,10 +107,10 @@ type TStaticMap = Map<
99
107
  >;
100
108
 
101
109
  type TResolutedOptions = Readonly<{
102
- allowLogsMethods: ("GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "OPTIONS")[];
103
- allowOrigins: string[];
104
- allowMethods: string[];
105
- allowHeaders: string[];
110
+ allowLogsMethods: Array<THttpMethods>;
111
+ allowOrigins: Array<string>;
112
+ allowMethods: Array<THttpMethods>;
113
+ allowHeaders: Array<string>;
106
114
  allowCredentials: boolean;
107
115
  staticOption?: Required<{
108
116
  path: string;
@@ -133,7 +141,7 @@ type TValidator = undefined | ICustomValidator;
133
141
 
134
142
  export class Application<TRootClass extends Object = Object> {
135
143
  #preLaunchData: TPreLaunch;
136
- #inputedConstructorKeys: any[];
144
+ #inputedConstructorKeys: Array<any>;
137
145
  #injector = new Injector();
138
146
  #staticMap: TStaticMap = new Map();
139
147
  #resolutedOptions: TResolutedOptions;
@@ -170,14 +178,7 @@ export class Application<TRootClass extends Object = Object> {
170
178
  ? ["*"]
171
179
  : this.options.cors.origins
172
180
  : [this.options.cors.origins !== "*" ? this.options.cors.origins : "*"],
173
- allowMethods: this.options.cors?.methods || [
174
- "GET",
175
- "POST",
176
- "PUT",
177
- "PATCH",
178
- "DELETE",
179
- "OPTIONS"
180
- ],
181
+ allowMethods: this.options.cors?.methods || httpMethods,
181
182
  allowCredentials: !this.options.cors?.credentials ? false : true,
182
183
  allowHeaders:
183
184
  !this.options.cors?.headers || this.options.cors.headers.includes("*")
@@ -299,6 +300,25 @@ export class Application<TRootClass extends Object = Object> {
299
300
  .set(queryArgsKey, query);
300
301
 
301
302
  try {
303
+ const validateRequestMethod = httpMethodsStandardization(method);
304
+
305
+ if (!validateRequestMethod) {
306
+ return this.finalizeResponse(
307
+ new Response(
308
+ JSON.stringify({
309
+ httpCode: 405,
310
+ message: "Method Not Allowed.",
311
+ data: undefined
312
+ }),
313
+ {
314
+ status: 405,
315
+ statusText: "Method Not Allowed.",
316
+ headers: responseHeaders
317
+ }
318
+ )
319
+ );
320
+ }
321
+
302
322
  const isUpgradable = isWebSocketUpgrade(request);
303
323
 
304
324
  let collection:
@@ -313,10 +333,10 @@ export class Application<TRootClass extends Object = Object> {
313
333
  if (isUpgradable) {
314
334
  for (const availableModuleResolution of resolutedModules) {
315
335
  const routeResult =
316
- availableModuleResolution.webSocketHttpRouterGroup.find(
317
- url.pathname,
318
- request.method as keyof THttpMethods
319
- );
336
+ availableModuleResolution.webSocketHttpRouterGroup.find({
337
+ pathname: url.pathname,
338
+ method: method
339
+ });
320
340
 
321
341
  if (routeResult) {
322
342
  collection = Object.freeze({
@@ -492,10 +512,10 @@ export class Application<TRootClass extends Object = Object> {
492
512
  }
493
513
 
494
514
  for (const availableModuleResolution of resolutedModules) {
495
- const routeResult = availableModuleResolution.controllerRouterGroup.find(
496
- url.pathname,
497
- method as keyof THttpMethods
498
- );
515
+ const routeResult = availableModuleResolution.controllerRouterGroup.find({
516
+ pathname: url.pathname,
517
+ method: method
518
+ });
499
519
 
500
520
  if (routeResult) {
501
521
  collection = Object.freeze({
@@ -1304,7 +1324,9 @@ export class Application<TRootClass extends Object = Object> {
1304
1324
  httpMetadata: []
1305
1325
  };
1306
1326
 
1307
- const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
1327
+ const router = new HttpRouter({
1328
+ alias: `/${prefix || ""}/${controllerMetadata.prefix}`
1329
+ });
1308
1330
 
1309
1331
  controllerMetadata.httpMetadata.forEach((routeMetadata) => {
1310
1332
  if (typeof routeMetadata.descriptor.value !== "function") {
@@ -1313,7 +1335,7 @@ export class Application<TRootClass extends Object = Object> {
1313
1335
 
1314
1336
  const route = router.route(routeMetadata.path);
1315
1337
  const handler = routeMetadata.descriptor.value.bind(controller);
1316
- const routeArgument = Object.freeze({
1338
+ const httpRouteModel = Object.freeze({
1317
1339
  class: controllerConstructor,
1318
1340
  funcName: routeMetadata.methodName,
1319
1341
  func: handler,
@@ -1322,17 +1344,17 @@ export class Application<TRootClass extends Object = Object> {
1322
1344
 
1323
1345
  switch (routeMetadata.httpMethod) {
1324
1346
  case "GET":
1325
- return route.get(routeArgument);
1347
+ return route.get({ model: httpRouteModel });
1326
1348
  case "POST":
1327
- return route.post(routeArgument);
1349
+ return route.post({ model: httpRouteModel });
1328
1350
  case "PUT":
1329
- return route.put(routeArgument);
1351
+ return route.put({ model: httpRouteModel });
1330
1352
  case "PATCH":
1331
- return route.patch(routeArgument);
1353
+ return route.patch({ model: httpRouteModel });
1332
1354
  case "DELETE":
1333
- return route.delete(routeArgument);
1355
+ return route.delete({ model: httpRouteModel });
1334
1356
  case "OPTIONS":
1335
- return route.options(routeArgument);
1357
+ return route.options({ model: httpRouteModel });
1336
1358
  }
1337
1359
  });
1338
1360
 
@@ -1382,7 +1404,9 @@ export class Application<TRootClass extends Object = Object> {
1382
1404
  const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
1383
1405
 
1384
1406
  //#region [HTTP ROUTER]
1385
- const router = new HttpRouter(fullPrefix);
1407
+ const router = new HttpRouter({
1408
+ alias: fullPrefix
1409
+ });
1386
1410
 
1387
1411
  for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
1388
1412
  if (typeof httpMetadata.descriptor?.value !== "function") {
@@ -1391,7 +1415,7 @@ export class Application<TRootClass extends Object = Object> {
1391
1415
 
1392
1416
  const route = router.route(httpMetadata.path);
1393
1417
  const handler = httpMetadata.descriptor.value.bind(webSocket);
1394
- const routeArgument = Object.freeze({
1418
+ const httpRouteModel = Object.freeze({
1395
1419
  class: webSocketConstructor,
1396
1420
  funcName: httpMetadata.methodName,
1397
1421
  func: handler,
@@ -1400,10 +1424,10 @@ export class Application<TRootClass extends Object = Object> {
1400
1424
 
1401
1425
  switch (httpMetadata.httpMethod) {
1402
1426
  case "GET":
1403
- route.get(routeArgument);
1427
+ route.get({ model: httpRouteModel });
1404
1428
  break;
1405
1429
  case "POST":
1406
- route.post(routeArgument);
1430
+ route.post({ model: httpRouteModel });
1407
1431
  break;
1408
1432
  }
1409
1433
  }
@@ -1453,21 +1477,31 @@ export class Application<TRootClass extends Object = Object> {
1453
1477
 
1454
1478
  if (contentType.includes("application/json")) {
1455
1479
  return this.finalizeResponse(
1456
- new Response(data instanceof ReadableStream ? data : JSON.stringify(data), {
1457
- status: status,
1458
- statusText: statusText,
1459
- headers: headers
1460
- })
1480
+ new Response(
1481
+ !data
1482
+ ? undefined
1483
+ : data instanceof ReadableStream
1484
+ ? data
1485
+ : JSON.stringify(data),
1486
+ {
1487
+ status: !data ? 204 : status,
1488
+ statusText: statusText,
1489
+ headers: headers
1490
+ }
1491
+ )
1461
1492
  );
1462
1493
  }
1463
1494
 
1464
1495
  if (contentType.includes("text/plain") || contentType.includes("text/html")) {
1465
1496
  return this.finalizeResponse(
1466
- new Response(data instanceof ReadableStream ? data : String(data), {
1467
- status: status,
1468
- statusText: statusText,
1469
- headers: headers
1470
- })
1497
+ new Response(
1498
+ !data ? undefined : data instanceof ReadableStream ? data : String(data),
1499
+ {
1500
+ status: !data ? 204 : status,
1501
+ statusText: statusText,
1502
+ headers: headers
1503
+ }
1504
+ )
1471
1505
  );
1472
1506
  }
1473
1507
 
@@ -1501,7 +1535,11 @@ export class Application<TRootClass extends Object = Object> {
1501
1535
  }
1502
1536
 
1503
1537
  return this.finalizeResponse(
1504
- new Response(String(data), { status: status, statusText: statusText, headers: headers })
1538
+ new Response(!data ? undefined : String(data), {
1539
+ status: !data ? 204 : status,
1540
+ statusText: statusText,
1541
+ headers: headers
1542
+ })
1505
1543
  );
1506
1544
  }
1507
1545