@zerooneit/expressive-tea 1.3.0-beta.5 → 2.0.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.
Files changed (77) hide show
  1. package/.gitattributes +4 -0
  2. package/.swcrc +61 -0
  3. package/README.md +564 -174
  4. package/classes/Boot.d.ts +94 -3
  5. package/classes/Boot.js +171 -51
  6. package/classes/Engine.d.ts +59 -10
  7. package/classes/Engine.js +72 -11
  8. package/classes/EngineRegistry.d.ts +154 -0
  9. package/classes/EngineRegistry.js +247 -0
  10. package/classes/LoadBalancer.js +2 -5
  11. package/classes/ProxyRoute.d.ts +3 -3
  12. package/classes/ProxyRoute.js +5 -5
  13. package/classes/Settings.d.ts +31 -2
  14. package/classes/Settings.js +64 -11
  15. package/decorators/annotations.d.ts +1 -1
  16. package/decorators/annotations.js +17 -17
  17. package/decorators/env.d.ts +145 -0
  18. package/decorators/env.js +177 -0
  19. package/decorators/health.d.ts +115 -0
  20. package/decorators/health.js +124 -0
  21. package/decorators/module.d.ts +15 -15
  22. package/decorators/module.js +14 -23
  23. package/decorators/proxy.d.ts +26 -11
  24. package/decorators/proxy.js +35 -45
  25. package/decorators/router.d.ts +17 -16
  26. package/decorators/router.js +32 -52
  27. package/decorators/server.d.ts +8 -8
  28. package/decorators/server.js +48 -50
  29. package/engines/health/index.d.ts +120 -0
  30. package/engines/health/index.js +179 -0
  31. package/engines/http/index.d.ts +6 -7
  32. package/engines/http/index.js +22 -17
  33. package/engines/index.d.ts +32 -0
  34. package/engines/index.js +112 -0
  35. package/engines/socketio/index.d.ts +2 -1
  36. package/engines/socketio/index.js +16 -6
  37. package/engines/teacup/index.d.ts +13 -0
  38. package/engines/teacup/index.js +61 -11
  39. package/engines/teapot/index.d.ts +15 -2
  40. package/engines/teapot/index.js +61 -13
  41. package/engines/websocket/index.d.ts +4 -1
  42. package/engines/websocket/index.js +10 -2
  43. package/eslint.config.mjs +138 -0
  44. package/exceptions/RequestExceptions.d.ts +3 -3
  45. package/helpers/boot-helper.d.ts +6 -6
  46. package/helpers/boot-helper.js +30 -24
  47. package/helpers/decorators.js +7 -6
  48. package/helpers/promise-helper.d.ts +1 -1
  49. package/helpers/promise-helper.js +1 -2
  50. package/helpers/server.d.ts +32 -6
  51. package/helpers/server.js +101 -61
  52. package/helpers/teapot-helper.d.ts +5 -8
  53. package/helpers/teapot-helper.js +39 -11
  54. package/helpers/websocket-helper.d.ts +3 -5
  55. package/helpers/websocket-helper.js +3 -3
  56. package/interfaces/index.d.ts +1 -1
  57. package/inversify.config.d.ts +4 -4
  58. package/inversify.config.js +1 -1
  59. package/libs/utilities.d.ts +21910 -0
  60. package/libs/utilities.js +420 -0
  61. package/mixins/module.d.ts +45 -0
  62. package/mixins/module.js +71 -0
  63. package/mixins/proxy.d.ts +46 -0
  64. package/mixins/proxy.js +86 -0
  65. package/mixins/route.d.ts +48 -0
  66. package/mixins/route.js +96 -0
  67. package/package.json +91 -69
  68. package/services/DependencyInjection.d.ts +95 -7
  69. package/services/DependencyInjection.js +123 -5
  70. package/services/WebsocketService.d.ts +4 -6
  71. package/services/WebsocketService.js +5 -3
  72. package/types/core.d.ts +14 -0
  73. package/types/core.js +2 -0
  74. package/types/injection-types.d.ts +6 -0
  75. package/types/injection-types.js +10 -0
  76. package/types/inversify.d.ts +5 -0
  77. package/types/inversify.js +3 -0
@@ -25,7 +25,7 @@
25
25
  export declare class GenericRequestException extends Error {
26
26
  statusCode: number;
27
27
  message: string;
28
- constructor(message: any, statusCode?: number);
28
+ constructor(message: string, statusCode?: number);
29
29
  }
30
30
  /**
31
31
  * Shortcut Exception for 400 HTTP Errors (Bad Request).
@@ -48,7 +48,7 @@ export declare class GenericRequestException extends Error {
48
48
  * }
49
49
  */
50
50
  export declare class BadRequestException extends GenericRequestException {
51
- constructor(message?: string | never);
51
+ constructor(message?: string);
52
52
  }
53
53
  /**
54
54
  * Shortcut Exception for 401 HTTP Errors (Unauthorized Request).
@@ -71,5 +71,5 @@ export declare class BadRequestException extends GenericRequestException {
71
71
  * }
72
72
  */
73
73
  export declare class UnauthorizedException extends GenericRequestException {
74
- constructor(message?: string | never);
74
+ constructor(message?: string);
75
75
  }
@@ -1,7 +1,7 @@
1
- import { BOOT_STAGES } from '@expressive-tea/commons/constants';
2
- import { Express } from 'express';
3
- import Boot from '../classes/Boot';
1
+ import { BOOT_STAGES } from '@expressive-tea/commons';
2
+ import { type Express } from 'express';
3
+ import type Boot from '../classes/Boot';
4
4
  export declare function resolveStage(stage: BOOT_STAGES, ctx: Boot, server: Express, ...extraArgs: unknown[]): Promise<void>;
5
- export declare function resolveDirectives(instance: typeof Boot | Boot, server: Express): Promise<void>;
6
- export declare function resolveStatic(instance: typeof Boot | Boot, server: Express): Promise<void>;
7
- export declare function resolveProxy(ProxyContainer: any, server: Express): Promise<void>;
5
+ export declare function resolveDirectives(instance: typeof Boot | Boot, server: Express): void;
6
+ export declare function resolveStatic(instance: typeof Boot | Boot, server: Express): void;
7
+ export declare function resolveProxy(ProxyContainer: any, server: Express): void;
@@ -1,17 +1,21 @@
1
1
  "use strict";
2
- // tslint:disable:no-duplicate-imports
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.resolveProxy = exports.resolveStatic = exports.resolveDirectives = exports.resolveStage = void 0;
5
- const constants_1 = require("@expressive-tea/commons/constants");
3
+ exports.resolveStage = resolveStage;
4
+ exports.resolveDirectives = resolveDirectives;
5
+ exports.resolveStatic = resolveStatic;
6
+ exports.resolveProxy = resolveProxy;
7
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return */
8
+ const commons_1 = require("@expressive-tea/commons");
6
9
  const express = require("express");
7
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
8
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
10
+ const commons_2 = require("@expressive-tea/commons");
11
+ const commons_3 = require("@expressive-tea/commons");
9
12
  const BootLoaderExceptions_1 = require("../exceptions/BootLoaderExceptions");
13
+ const DependencyInjection_1 = require("../services/DependencyInjection");
10
14
  async function resolveStage(stage, ctx, server, ...extraArgs) {
11
15
  try {
12
16
  await bootloaderResolve(stage, server, ctx, ...extraArgs);
13
- if (stage === constants_1.BOOT_STAGES.APPLICATION) {
14
- await resolveModules(ctx, server);
17
+ if (stage === commons_1.BOOT_STAGES.APPLICATION) {
18
+ resolveModules(ctx, server);
15
19
  }
16
20
  }
17
21
  catch (e) {
@@ -20,16 +24,16 @@ async function resolveStage(stage, ctx, server, ...extraArgs) {
20
24
  }
21
25
  }
22
26
  }
23
- exports.resolveStage = resolveStage;
24
- async function resolveDirectives(instance, server) {
25
- const registeredDirectives = Metadata_1.default.get(constants_1.REGISTERED_DIRECTIVES_KEY, (0, object_helper_1.getClass)(instance)) || [];
27
+ function resolveDirectives(instance, server) {
28
+ const registeredDirectives = commons_2.Metadata.get(commons_1.REGISTERED_DIRECTIVES_KEY, (0, commons_3.getClass)(instance)) || [];
26
29
  registeredDirectives.forEach((options) => {
27
- server.set.call(server, options.name, ...options.settings);
30
+ // @ts-expect-error Settings can be any parameter
31
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
32
+ server.set(options.name, ...options.settings);
28
33
  });
29
34
  }
30
- exports.resolveDirectives = resolveDirectives;
31
- async function resolveStatic(instance, server) {
32
- const registeredStatic = Metadata_1.default.get(constants_1.REGISTERED_STATIC_KEY, (0, object_helper_1.getClass)(instance)) || [];
35
+ function resolveStatic(instance, server) {
36
+ const registeredStatic = commons_2.Metadata.get(commons_1.REGISTERED_STATIC_KEY, (0, commons_3.getClass)(instance)) || [];
33
37
  registeredStatic.forEach((staticOptions) => {
34
38
  if (staticOptions.virtual) {
35
39
  server.use(staticOptions.virtual, express.static(staticOptions.root, staticOptions.options));
@@ -39,21 +43,23 @@ async function resolveStatic(instance, server) {
39
43
  }
40
44
  });
41
45
  }
42
- exports.resolveStatic = resolveStatic;
43
- async function resolveProxy(ProxyContainer, server) {
46
+ function resolveProxy(ProxyContainer, server) {
44
47
  const proxyContainer = new ProxyContainer();
45
48
  proxyContainer.__register(server);
46
49
  }
47
- exports.resolveProxy = resolveProxy;
48
- async function resolveModules(instance, server) {
49
- const registeredModules = Metadata_1.default.get(constants_1.REGISTERED_MODULE_KEY, instance, 'start') || [];
50
- registeredModules.forEach(Module => {
51
- const moduleInstance = new Module();
50
+ function resolveModules(instance, server) {
51
+ // Metadata is stored on the class by decorators, so we need to get the constructor
52
+ // If instance is already a class (typeof === 'function'), use it directly
53
+ // If instance is an object, get its constructor
54
+ const target = typeof instance === 'function' ? instance : instance.constructor;
55
+ const registeredModules = commons_2.Metadata.get(commons_1.REGISTERED_MODULE_KEY, target, 'start') || [];
56
+ for (const Module of registeredModules) {
57
+ const moduleInstance = (0, DependencyInjection_1.getInstanceOf)(Module);
52
58
  moduleInstance.__register(server);
53
- });
59
+ }
54
60
  }
55
61
  async function bootloaderResolve(STAGE, server, instance, ...args) {
56
- const bootLoader = Metadata_1.default.get(constants_1.BOOT_STAGES_KEY, (0, object_helper_1.getClass)(instance)) || constants_1.STAGES_INIT;
62
+ const bootLoader = commons_2.Metadata.get(commons_1.BOOT_STAGES_KEY, (0, commons_3.getClass)(instance)) || commons_1.STAGES_INIT;
57
63
  for (const loader of bootLoader[STAGE] || []) {
58
64
  try {
59
65
  await selectLoaderType(loader, server, ...args);
@@ -63,7 +69,7 @@ async function bootloaderResolve(STAGE, server, instance, ...args) {
63
69
  }
64
70
  }
65
71
  }
66
- async function selectLoaderType(loader, server, ...args) {
72
+ function selectLoaderType(loader, server, ...args) {
67
73
  return loader.method(server, ...args);
68
74
  }
69
75
  function checkIfStageFails(e) {
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.addAnnotation = void 0;
4
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
5
- const constants_1 = require("@expressive-tea/commons/constants");
3
+ exports.addAnnotation = addAnnotation;
4
+ const commons_1 = require("@expressive-tea/commons");
5
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
6
+ const commons_2 = require("@expressive-tea/commons");
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
8
  function addAnnotation(type, target, propertyKey, ...args) {
7
- const annotations = Metadata_1.default.get(constants_1.ROUTER_ANNOTATIONS_KEY, target, propertyKey) || [];
9
+ const annotations = commons_1.Metadata.get(commons_2.ROUTER_ANNOTATIONS_KEY, target, propertyKey) || [];
8
10
  annotations.unshift({
9
11
  arguments: args,
10
12
  type
11
13
  });
12
- Metadata_1.default.set(constants_1.ROUTER_ANNOTATIONS_KEY, annotations, target, propertyKey);
14
+ commons_1.Metadata.set(commons_2.ROUTER_ANNOTATIONS_KEY, annotations, target, propertyKey);
13
15
  }
14
- exports.addAnnotation = addAnnotation;
@@ -1 +1 @@
1
- export declare function delay(ms: number): Promise<unknown>;
1
+ export declare function delay(ms: number): Promise<void>;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.delay = void 0;
3
+ exports.delay = delay;
4
4
  async function delay(ms) {
5
5
  return new Promise(resolve => setTimeout(resolve, ms));
6
6
  }
7
- exports.delay = delay;
@@ -1,9 +1,35 @@
1
- import { NextFunction, Request, Response } from 'express';
2
- import { ExpressiveTeaAnnotations, ExpressiveTeaArgumentOptions } from '@expressive-tea/commons/interfaces';
3
- export declare function autoResponse(request: Request, response: Response, annotations: ExpressiveTeaAnnotations[], responseResult?: any): void;
4
- export declare function executeRequest(request: Request, response: Response, next: NextFunction): Promise<void>;
1
+ import { type NextFunction, type Request, type Response } from 'express';
2
+ import { type ExpressiveTeaAnnotations, type ExpressiveTeaArgumentOptions } from '@expressive-tea/commons';
3
+ import { type ExpressiveTeaHandlerOptionsWithInstrospectedArgs } from '../interfaces';
4
+ import { TFunction } from '../types/core';
5
+ import { type ExpressiveTeaServerProps } from '@expressive-tea/commons';
6
+ interface ExecuteRequestContext {
7
+ options: ExpressiveTeaHandlerOptionsWithInstrospectedArgs;
8
+ decoratedArguments: ExpressiveTeaArgumentOptions[];
9
+ annotations: ExpressiveTeaAnnotations[];
10
+ self: any;
11
+ }
12
+ export interface FileSettingsResult {
13
+ config: ExpressiveTeaServerProps;
14
+ source: string | null;
15
+ }
16
+ export declare function autoResponse(_: any, response: Response, annotations: ExpressiveTeaAnnotations[], responseResult?: any): void;
17
+ export declare function executeRequest(this: ExecuteRequestContext, request: Request, response: Response, next: NextFunction): Promise<void>;
5
18
  export declare function mapArguments(decoratedArguments: ExpressiveTeaArgumentOptions[], request: Request, response: Response, next: NextFunction, introspectedArgs?: string[]): any[];
6
19
  export declare function extractParameters(target: unknown, args?: string | string[], propertyName?: string): any;
7
20
  export declare function generateRoute(route: string, verb: string, ...settings: any): (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;
8
- export declare function router(verb: string, route: string, target: any, handler: (...args: any[]) => void | any | Promise<any>, propertyKey: string | symbol, settings?: any): void;
9
- export declare function fileSettings(): any;
21
+ export declare function router(verb: string, route: string, target: any, handler: TFunction, propertyKey: string | symbol, settings?: any): void;
22
+ /**
23
+ * Load configuration from .expressive-tea files.
24
+ *
25
+ * Supports YAML (.yaml, .yml) and JSON formats with priority order:
26
+ * 1. .expressive-tea.yaml (highest)
27
+ * 2. .expressive-tea.yml
28
+ * 3. .expressive-tea (JSON, lowest)
29
+ *
30
+ * @returns Configuration object and source file path
31
+ * @throws {Error} If config file is invalid (JSON/YAML parse error)
32
+ * @since 2.0.1
33
+ */
34
+ export declare function fileSettings(): FileSettingsResult;
35
+ export {};
package/helpers/server.js CHANGED
@@ -1,101 +1,141 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fileSettings = exports.router = exports.generateRoute = exports.extractParameters = exports.mapArguments = exports.executeRequest = exports.autoResponse = void 0;
4
- const lodash_1 = require("lodash");
5
- const Metadata_1 = require("@expressive-tea/commons/classes/Metadata");
6
- const constants_1 = require("@expressive-tea/commons/constants");
7
- const RequestExceptions_1 = require("../exceptions/RequestExceptions");
8
- const object_helper_1 = require("@expressive-tea/commons/helpers/object-helper");
9
- const fs = require("fs");
10
- function autoResponse(request, response, annotations, responseResult) {
11
- const view = (0, lodash_1.find)(annotations, { type: 'view' });
12
- if (view) {
13
- return response.render(view.arguments[0], responseResult);
3
+ exports.autoResponse = autoResponse;
4
+ exports.executeRequest = executeRequest;
5
+ exports.mapArguments = mapArguments;
6
+ exports.extractParameters = extractParameters;
7
+ exports.generateRoute = generateRoute;
8
+ exports.router = router;
9
+ exports.fileSettings = fileSettings;
10
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */
11
+ const utilities_1 = require("../libs/utilities");
12
+ const commons_1 = require("@expressive-tea/commons");
13
+ const commons_2 = require("@expressive-tea/commons");
14
+ const commons_3 = require("@expressive-tea/commons");
15
+ const fs = require("node:fs");
16
+ const yaml = require("js-yaml");
17
+ const path = require("node:path");
18
+ function autoResponse(_, response, annotations, responseResult) {
19
+ const view = (0, utilities_1.find)(annotations, { type: 'view' });
20
+ if (view && view.arguments) {
21
+ response.render(view.arguments[0], responseResult);
22
+ return;
14
23
  }
15
- response.send((0, lodash_1.isNumber)(responseResult) ? responseResult.toString() : responseResult);
24
+ response.send((0, utilities_1.isNumber)(responseResult) ? responseResult.toString() : responseResult);
16
25
  }
17
- exports.autoResponse = autoResponse;
18
26
  async function executeRequest(request, response, next) {
19
- try {
20
- let isNextUsed = false;
21
- const nextWrapper = () => (error) => {
22
- next(error);
27
+ let isNextUsed = false;
28
+ const nextWrapper = (error) => {
29
+ if (error) {
23
30
  isNextUsed = true;
24
- };
25
- const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper(), this.options.introspectedArgs));
26
- if (!response.headersSent && !isNextUsed) {
27
- autoResponse(request, response, this.annotations, result);
31
+ return next(error);
28
32
  }
33
+ isNextUsed = true;
34
+ next();
35
+ };
36
+ const result = await this.options.handler.apply(this.self, mapArguments(this.decoratedArguments, request, response, nextWrapper, this.options.introspectedArgs));
37
+ if (!response.headersSent && !isNextUsed) {
38
+ autoResponse(request, response, this.annotations, result);
29
39
  }
30
- catch (e) {
31
- if (e instanceof RequestExceptions_1.GenericRequestException) {
32
- return next(e);
33
- }
34
- next(new RequestExceptions_1.GenericRequestException(e.message || 'System Error'));
35
- }
40
+ // Express 5 handles async rejections automatically
36
41
  }
37
- exports.executeRequest = executeRequest;
38
42
  function mapArguments(decoratedArguments, request, response, next, introspectedArgs = []) {
39
- return (0, lodash_1.chain)(decoratedArguments)
43
+ return (0, utilities_1.chain)(decoratedArguments)
40
44
  .sortBy('index')
41
45
  .map((argument) => {
42
46
  switch (argument.type) {
43
- case constants_1.ARGUMENT_TYPES.REQUEST:
47
+ case commons_2.ARGUMENT_TYPES.REQUEST:
44
48
  return request;
45
- case constants_1.ARGUMENT_TYPES.RESPONSE:
49
+ case commons_2.ARGUMENT_TYPES.RESPONSE:
46
50
  return response;
47
- case constants_1.ARGUMENT_TYPES.NEXT:
51
+ case commons_2.ARGUMENT_TYPES.NEXT:
48
52
  return next;
49
- case constants_1.ARGUMENT_TYPES.QUERY:
50
- return extractParameters(request.query, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
51
- case constants_1.ARGUMENT_TYPES.BODY:
52
- return extractParameters(request.body, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
53
- case constants_1.ARGUMENT_TYPES.GET_PARAM:
54
- return extractParameters(request.params, argument.arguments, (0, lodash_1.get)(introspectedArgs, argument.index));
53
+ case commons_2.ARGUMENT_TYPES.QUERY:
54
+ return extractParameters(request.query, argument.arguments, (0, utilities_1.get)(introspectedArgs, argument.index));
55
+ case commons_2.ARGUMENT_TYPES.BODY:
56
+ return extractParameters(request.body, argument.arguments, (0, utilities_1.get)(introspectedArgs, argument.index));
57
+ case commons_2.ARGUMENT_TYPES.GET_PARAM:
58
+ return extractParameters(request.params, argument.arguments, (0, utilities_1.get)(introspectedArgs, argument.index));
55
59
  default:
56
- return;
60
+ return undefined;
57
61
  }
58
62
  })
59
- .thru((args) => (0, lodash_1.size)(args) ? args : [request, response, next])
63
+ .thru((args) => (0, utilities_1.size)(args) ? args : [request, response, next])
60
64
  .value();
61
65
  }
62
- exports.mapArguments = mapArguments;
63
66
  function extractParameters(target, args, propertyName) {
64
67
  if (!args && !target) {
65
68
  return;
66
69
  }
67
- if ((0, lodash_1.size)(args)) {
70
+ if (args && (0, utilities_1.size)(args)) {
68
71
  if (Array.isArray(args)) {
69
- return (0, lodash_1.pick)(target, args);
72
+ return (0, utilities_1.pick)(target, args);
70
73
  }
71
- return (0, lodash_1.get)(target, args);
74
+ return (0, utilities_1.get)(target, args);
72
75
  }
73
- if ((0, lodash_1.has)(target, propertyName)) {
74
- return (0, lodash_1.get)(target, propertyName);
76
+ if (propertyName && (0, utilities_1.has)(target, propertyName)) {
77
+ return (0, utilities_1.get)(target, propertyName);
75
78
  }
76
79
  return target;
77
80
  }
78
- exports.extractParameters = extractParameters;
79
81
  function generateRoute(route, verb, ...settings) {
80
- return (target, propertyKey, descriptor) => router(verb, route, target, descriptor.value, propertyKey, settings);
82
+ return (target, propertyKey, descriptor) => {
83
+ router(verb, route, target, descriptor.value, propertyKey, settings);
84
+ };
81
85
  }
82
- exports.generateRoute = generateRoute;
83
86
  function router(verb, route, target, handler, propertyKey, settings) {
84
- const introspectedArgs = (0, object_helper_1.getOwnArgumentNames)(handler);
85
- const existedRoutesHandlers = Metadata_1.default.get(constants_1.ROUTER_HANDLERS_KEY, target) || [];
87
+ const introspectedArgs = (0, commons_3.getOwnArgumentNames)(handler);
88
+ const existedRoutesHandlers = commons_1.Metadata.get(commons_2.ROUTER_HANDLERS_KEY, target) || [];
86
89
  existedRoutesHandlers.unshift({ verb, route, handler, target, propertyKey, settings, introspectedArgs });
87
- Metadata_1.default.set(constants_1.ROUTER_HANDLERS_KEY, existedRoutesHandlers, target);
90
+ commons_1.Metadata.set(commons_2.ROUTER_HANDLERS_KEY, existedRoutesHandlers, target);
88
91
  }
89
- exports.router = router;
92
+ /**
93
+ * Load configuration from .expressive-tea files.
94
+ *
95
+ * Supports YAML (.yaml, .yml) and JSON formats with priority order:
96
+ * 1. .expressive-tea.yaml (highest)
97
+ * 2. .expressive-tea.yml
98
+ * 3. .expressive-tea (JSON, lowest)
99
+ *
100
+ * @returns Configuration object and source file path
101
+ * @throws {Error} If config file is invalid (JSON/YAML parse error)
102
+ * @since 2.0.1
103
+ */
90
104
  function fileSettings() {
91
- try {
92
- if (fs.existsSync('.expressive-tea')) {
93
- const configString = fs.readFileSync('.expressive-tea');
94
- return JSON.parse(configString.toString());
105
+ const cwd = process.cwd();
106
+ // Priority order: YAML > YML > JSON
107
+ const configFiles = [
108
+ { path: '.expressive-tea.yaml', type: 'yaml' },
109
+ { path: '.expressive-tea.yml', type: 'yaml' },
110
+ { path: '.expressive-tea', type: 'json' }
111
+ ];
112
+ for (const file of configFiles) {
113
+ const filePath = path.join(cwd, file.path);
114
+ if (fs.existsSync(filePath)) {
115
+ try {
116
+ const content = fs.readFileSync(filePath, 'utf-8');
117
+ let config;
118
+ if (file.type === 'yaml') {
119
+ const parsed = yaml.load(content);
120
+ // yaml.load returns undefined for empty strings and null for whitespace/comments
121
+ // Treat empty YAML files as empty configuration objects
122
+ config = (parsed !== null && parsed !== void 0 ? parsed : {});
123
+ }
124
+ else {
125
+ config = JSON.parse(content);
126
+ }
127
+ // Debug log which file was loaded
128
+ console.debug(`[Expressive Tea] Loaded configuration from: ${file.path}`);
129
+ return { config, source: file.path };
130
+ }
131
+ catch (error) {
132
+ const errorMsg = file.type === 'yaml'
133
+ ? `Invalid YAML in ${file.path}: ${error.message}`
134
+ : `Invalid JSON in ${file.path}: ${error.message}`;
135
+ throw new Error(errorMsg);
136
+ }
95
137
  }
96
138
  }
97
- catch (e) {
98
- return {};
99
- }
139
+ // No config file found
140
+ return { config: {}, source: null };
100
141
  }
101
- exports.fileSettings = fileSettings;
@@ -1,15 +1,12 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- import { KeyPairSyncResult } from 'crypto';
4
- import { NextFunction, Request, Response } from 'express';
5
- import ProxyRoute from '../classes/ProxyRoute';
1
+ import { type KeyPairSyncResult } from 'node:crypto';
2
+ import { type NextFunction, type Request, type Response } from 'express';
3
+ import type ProxyRoute from '../classes/ProxyRoute';
6
4
  export interface EncryptedMessage {
7
5
  iv: string;
8
6
  message: string;
7
+ authTag: string;
9
8
  }
10
- export interface TeaGatewayMessage {
11
- [property: string]: any;
12
- }
9
+ export type TeaGatewayMessage = Record<string, any>;
13
10
  export default class TeaGatewayHelper {
14
11
  static encrypt(data: TeaGatewayMessage, signature: Buffer): EncryptedMessage;
15
12
  static decrypt(data: EncryptedMessage, signature: Buffer): TeaGatewayMessage;
@@ -1,20 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const crypto = require("crypto");
3
+ const crypto = require("node:crypto");
4
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */
5
+ const node_crypto_1 = require("node:crypto");
4
6
  class TeaGatewayHelper {
5
7
  static encrypt(data, signature) {
6
8
  const iv = crypto.randomBytes(16);
7
9
  const packet = JSON.stringify(data);
8
- const cipher = crypto.createCipheriv('aes-256-ctr', signature, iv);
10
+ // HKDF key derivation - separate encryption key from signature
11
+ const derivedKey = Buffer.from(crypto.hkdfSync('sha256', signature, Buffer.alloc(32), 'expressive-tea-encryption', 32));
12
+ // AES-256-GCM - authenticated encryption
13
+ const cipher = crypto.createCipheriv('aes-256-gcm', derivedKey, iv);
9
14
  const encrypted = Buffer.concat([cipher.update(packet), cipher.final()]);
10
- return { iv: iv.toString('hex'), message: encrypted.toString('base64') };
15
+ const authTag = cipher.getAuthTag();
16
+ return {
17
+ iv: iv.toString('hex'),
18
+ message: encrypted.toString('base64'),
19
+ authTag: authTag.toString('hex')
20
+ };
11
21
  }
12
22
  static decrypt(data, signature) {
23
+ // Input validation
24
+ if (!data || !data.iv || !data.message || !data.authTag) {
25
+ throw new Error('Invalid encrypted message format');
26
+ }
27
+ if (!signature || signature.length !== 64) {
28
+ throw new Error('Invalid signature');
29
+ }
13
30
  const iv = Buffer.from(data.iv, 'hex');
14
31
  const message = Buffer.from(data.message, 'base64');
15
- const decipher = crypto.createDecipheriv('aes-256-ctr', signature, iv);
16
- const decrypted = Buffer.concat([decipher.update(message), decipher.final()]);
17
- return JSON.parse(decrypted.toString());
32
+ const authTag = Buffer.from(data.authTag, 'hex');
33
+ // HKDF key derivation - same as encrypt
34
+ const derivedKey = Buffer.from(crypto.hkdfSync('sha256', signature, Buffer.alloc(32), 'expressive-tea-encryption', 32));
35
+ // AES-256-GCM with auth tag verification
36
+ const decipher = crypto.createDecipheriv('aes-256-gcm', derivedKey, iv);
37
+ decipher.setAuthTag(authTag);
38
+ try {
39
+ const decrypted = Buffer.concat([decipher.update(message), decipher.final()]);
40
+ return JSON.parse(decrypted.toString());
41
+ }
42
+ catch (_a) {
43
+ throw new Error('Decryption failed: message tampered or wrong key');
44
+ }
18
45
  }
19
46
  static sign(data, privateKey, passphrase) {
20
47
  return crypto.sign(null, Buffer.from(data), {
@@ -28,8 +55,7 @@ class TeaGatewayHelper {
28
55
  }, signature);
29
56
  }
30
57
  static generateKeys(passphrase) {
31
- const { generateKeyPairSync } = require('crypto');
32
- return generateKeyPairSync('ed25519', {
58
+ return (0, node_crypto_1.generateKeyPairSync)('ed25519', {
33
59
  modulusLength: 2048,
34
60
  publicKeyEncoding: {
35
61
  type: 'spki',
@@ -45,9 +71,11 @@ class TeaGatewayHelper {
45
71
  }
46
72
  static proxyResponse(proxyRoute, req, res, next) {
47
73
  const router = proxyRoute.registerRoute();
48
- if (!proxyRoute.hasClients())
49
- return next();
50
- return router(req, res, next);
74
+ if (!proxyRoute.hasClients()) {
75
+ next();
76
+ return;
77
+ }
78
+ router(req, res, next);
51
79
  }
52
80
  static httpSchema(schema) {
53
81
  if (schema.includes('teapot'))
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- import * as http from 'http';
4
- import * as https from 'https';
5
- export declare function initWebsocket(server: http.Server, secureServer: https.Server): Promise<void>;
1
+ import type * as http from 'http';
2
+ import type * as https from 'https';
3
+ export declare function initWebsocket(server: http.Server, secureServer: https.Server): void;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.initWebsocket = void 0;
3
+ exports.initWebsocket = initWebsocket;
4
4
  const WebsocketService_1 = require("../services/WebsocketService");
5
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5
6
  const WebSocket = require("ws");
6
7
  const Settings_1 = require("../classes/Settings");
7
- async function initWebsocket(server, secureServer) {
8
+ function initWebsocket(server, secureServer) {
8
9
  const settings = Settings_1.default.getInstance();
9
10
  const isDetached = settings.get('detachWebsocket');
10
11
  if (settings.get('startWebsocket')) {
@@ -17,4 +18,3 @@ async function initWebsocket(server, secureServer) {
17
18
  WebsocketService_1.default.getInstance().setHttpServer(secureServer);
18
19
  }
19
20
  }
20
- exports.initWebsocket = initWebsocket;
@@ -1,4 +1,4 @@
1
- import { ExpressiveTeaHandlerOptions } from '@expressive-tea/commons/interfaces';
1
+ import { type ExpressiveTeaHandlerOptions } from '@expressive-tea/commons';
2
2
  export interface ExpressiveTeaHandlerOptionsWithInstrospectedArgs extends ExpressiveTeaHandlerOptions {
3
3
  introspectedArgs: string[];
4
4
  }
@@ -1,9 +1,9 @@
1
1
  import { Container } from 'inversify';
2
2
  declare const container: Container;
3
3
  export declare const decorators: {
4
- lazyInject: (serviceIdentifier: string | symbol | import("inversify/lib/interfaces/interfaces").interfaces.Newable<any> | import("inversify/lib/interfaces/interfaces").interfaces.Abstract<any>) => (proto: any, key: string) => void;
5
- lazyInjectNamed: (serviceIdentifier: string | symbol | import("inversify/lib/interfaces/interfaces").interfaces.Newable<any> | import("inversify/lib/interfaces/interfaces").interfaces.Abstract<any>, named: string) => (proto: any, key: string) => void;
6
- lazyInjectTagged: (serviceIdentifier: string | symbol | import("inversify/lib/interfaces/interfaces").interfaces.Newable<any> | import("inversify/lib/interfaces/interfaces").interfaces.Abstract<any>, key: string, value: any) => (proto: any, propertyName: string) => void;
7
- lazyMultiInject: (serviceIdentifier: string | symbol | import("inversify/lib/interfaces/interfaces").interfaces.Newable<any> | import("inversify/lib/interfaces/interfaces").interfaces.Abstract<any>) => (proto: any, key: string) => void;
4
+ lazyInject: (serviceIdentifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>) => (proto: any, key: string) => void;
5
+ lazyInjectNamed: (serviceIdentifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>, named: string) => (proto: any, key: string) => void;
6
+ lazyInjectTagged: (serviceIdentifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>, key: string, value: any) => (proto: any, propertyName: string) => void;
7
+ lazyMultiInject: (serviceIdentifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>) => (proto: any, key: string) => void;
8
8
  };
9
9
  export default container;
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decorators = void 0;
4
4
  const inversify_1 = require("inversify");
5
5
  const inversify_inject_decorators_1 = require("inversify-inject-decorators");
6
- const container = new inversify_1.Container({ autoBindInjectable: true });
6
+ const container = new inversify_1.Container({ autobind: true });
7
7
  exports.decorators = (0, inversify_inject_decorators_1.default)(container);
8
8
  exports.default = container;