@bool-ts/core 2.1.3 → 2.2.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/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.1"
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({
@@ -475,9 +495,25 @@ export class Application<TRootClass extends Object = Object> {
475
495
  }
476
496
  }
477
497
 
498
+ for (const availableModuleResolution of resolutedModules) {
499
+ const routeResult = availableModuleResolution.controllerRouterGroup.find({
500
+ pathname: url.pathname,
501
+ method: method
502
+ });
503
+
504
+ if (routeResult) {
505
+ collection = Object.freeze({
506
+ route: routeResult,
507
+ resolution: availableModuleResolution
508
+ });
509
+ break;
510
+ }
511
+ }
512
+
478
513
  if (resolutedContainer) {
479
514
  const { context: newContext } = await this.httpFetcher({
480
515
  context: context,
516
+ route: collection?.route,
481
517
  resolutedMap: {
482
518
  injector: resolutedContainer.injector,
483
519
  startMiddlewareGroup: resolutedContainer.startMiddlewareGroup,
@@ -491,21 +527,6 @@ export class Application<TRootClass extends Object = Object> {
491
527
  context = newContext;
492
528
  }
493
529
 
494
- for (const availableModuleResolution of resolutedModules) {
495
- const routeResult = availableModuleResolution.controllerRouterGroup.find(
496
- url.pathname,
497
- method as keyof THttpMethods
498
- );
499
-
500
- if (routeResult) {
501
- collection = Object.freeze({
502
- route: routeResult,
503
- resolution: availableModuleResolution
504
- });
505
- break;
506
- }
507
- }
508
-
509
530
  if (!collection) {
510
531
  context
511
532
  .setOptions({ isStatic: false })
@@ -554,14 +575,16 @@ export class Application<TRootClass extends Object = Object> {
554
575
  latestResponseStatus = context.get<unknown>(responseStatusArgsKey, {
555
576
  isStatic: false
556
577
  }),
557
- latestResponseStatusText = context.get<unknown>(responseStatusArgsKey, {
578
+ latestResponseStatusText = context.get<unknown>(responseStatusTextArgsKey, {
558
579
  isStatic: false
559
580
  });
560
581
 
561
582
  return this.serializeResponse({
562
583
  status:
563
584
  typeof latestResponseStatus !== "number"
564
- ? undefined
585
+ ? method === "POST"
586
+ ? 201
587
+ : undefined
565
588
  : latestResponseStatus,
566
589
  statusText:
567
590
  typeof latestResponseStatusText !== "string"
@@ -1304,7 +1327,9 @@ export class Application<TRootClass extends Object = Object> {
1304
1327
  httpMetadata: []
1305
1328
  };
1306
1329
 
1307
- const router = new HttpRouter(`/${prefix || ""}/${controllerMetadata.prefix}`);
1330
+ const router = new HttpRouter({
1331
+ alias: `/${prefix || ""}/${controllerMetadata.prefix}`
1332
+ });
1308
1333
 
1309
1334
  controllerMetadata.httpMetadata.forEach((routeMetadata) => {
1310
1335
  if (typeof routeMetadata.descriptor.value !== "function") {
@@ -1313,7 +1338,7 @@ export class Application<TRootClass extends Object = Object> {
1313
1338
 
1314
1339
  const route = router.route(routeMetadata.path);
1315
1340
  const handler = routeMetadata.descriptor.value.bind(controller);
1316
- const routeArgument = Object.freeze({
1341
+ const httpRouteModel = Object.freeze({
1317
1342
  class: controllerConstructor,
1318
1343
  funcName: routeMetadata.methodName,
1319
1344
  func: handler,
@@ -1322,17 +1347,17 @@ export class Application<TRootClass extends Object = Object> {
1322
1347
 
1323
1348
  switch (routeMetadata.httpMethod) {
1324
1349
  case "GET":
1325
- return route.get(routeArgument);
1350
+ return route.get({ model: httpRouteModel });
1326
1351
  case "POST":
1327
- return route.post(routeArgument);
1352
+ return route.post({ model: httpRouteModel });
1328
1353
  case "PUT":
1329
- return route.put(routeArgument);
1354
+ return route.put({ model: httpRouteModel });
1330
1355
  case "PATCH":
1331
- return route.patch(routeArgument);
1356
+ return route.patch({ model: httpRouteModel });
1332
1357
  case "DELETE":
1333
- return route.delete(routeArgument);
1358
+ return route.delete({ model: httpRouteModel });
1334
1359
  case "OPTIONS":
1335
- return route.options(routeArgument);
1360
+ return route.options({ model: httpRouteModel });
1336
1361
  }
1337
1362
  });
1338
1363
 
@@ -1382,7 +1407,9 @@ export class Application<TRootClass extends Object = Object> {
1382
1407
  const fullPrefix = `/${prefix || ""}/${webSocketMetadata.prefix}`;
1383
1408
 
1384
1409
  //#region [HTTP ROUTER]
1385
- const router = new HttpRouter(fullPrefix);
1410
+ const router = new HttpRouter({
1411
+ alias: fullPrefix
1412
+ });
1386
1413
 
1387
1414
  for (const [_key, httpMetadata] of Object.entries(webSocketMetadata.http)) {
1388
1415
  if (typeof httpMetadata.descriptor?.value !== "function") {
@@ -1391,7 +1418,7 @@ export class Application<TRootClass extends Object = Object> {
1391
1418
 
1392
1419
  const route = router.route(httpMetadata.path);
1393
1420
  const handler = httpMetadata.descriptor.value.bind(webSocket);
1394
- const routeArgument = Object.freeze({
1421
+ const httpRouteModel = Object.freeze({
1395
1422
  class: webSocketConstructor,
1396
1423
  funcName: httpMetadata.methodName,
1397
1424
  func: handler,
@@ -1400,10 +1427,10 @@ export class Application<TRootClass extends Object = Object> {
1400
1427
 
1401
1428
  switch (httpMetadata.httpMethod) {
1402
1429
  case "GET":
1403
- route.get(routeArgument);
1430
+ route.get({ model: httpRouteModel });
1404
1431
  break;
1405
1432
  case "POST":
1406
- route.post(routeArgument);
1433
+ route.post({ model: httpRouteModel });
1407
1434
  break;
1408
1435
  }
1409
1436
  }
@@ -1453,21 +1480,31 @@ export class Application<TRootClass extends Object = Object> {
1453
1480
 
1454
1481
  if (contentType.includes("application/json")) {
1455
1482
  return this.finalizeResponse(
1456
- new Response(data instanceof ReadableStream ? data : JSON.stringify(data), {
1457
- status: status,
1458
- statusText: statusText,
1459
- headers: headers
1460
- })
1483
+ new Response(
1484
+ !data
1485
+ ? undefined
1486
+ : data instanceof ReadableStream
1487
+ ? data
1488
+ : JSON.stringify(data),
1489
+ {
1490
+ status: !data ? 204 : status,
1491
+ statusText: statusText,
1492
+ headers: headers
1493
+ }
1494
+ )
1461
1495
  );
1462
1496
  }
1463
1497
 
1464
1498
  if (contentType.includes("text/plain") || contentType.includes("text/html")) {
1465
1499
  return this.finalizeResponse(
1466
- new Response(data instanceof ReadableStream ? data : String(data), {
1467
- status: status,
1468
- statusText: statusText,
1469
- headers: headers
1470
- })
1500
+ new Response(
1501
+ !data ? undefined : data instanceof ReadableStream ? data : String(data),
1502
+ {
1503
+ status: !data ? 204 : status,
1504
+ statusText: statusText,
1505
+ headers: headers
1506
+ }
1507
+ )
1471
1508
  );
1472
1509
  }
1473
1510
 
@@ -1501,7 +1538,11 @@ export class Application<TRootClass extends Object = Object> {
1501
1538
  }
1502
1539
 
1503
1540
  return this.finalizeResponse(
1504
- new Response(String(data), { status: status, statusText: statusText, headers: headers })
1541
+ new Response(!data ? undefined : String(data), {
1542
+ status: !data ? 204 : status,
1543
+ statusText: statusText,
1544
+ headers: headers
1545
+ })
1505
1546
  );
1506
1547
  }
1507
1548
 
@@ -1541,7 +1582,7 @@ export class Application<TRootClass extends Object = Object> {
1541
1582
  }>;
1542
1583
  }>) {
1543
1584
  const contextOptions = { isStatic: true };
1544
- const context = (!outerContext ? new Context() : new Context(outerContext)).setOptions(
1585
+ const context = new Context(...(!outerContext ? [] : [outerContext])).setOptions(
1545
1586
  contextOptions
1546
1587
  );
1547
1588