@adaas/a-server 0.0.20 → 0.0.22

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/dist/index.js CHANGED
@@ -2,22 +2,8 @@
2
2
 
3
3
  var aConcept = require('@adaas/a-concept');
4
4
  var aUtils = require('@adaas/a-utils');
5
- var http = require('http');
6
- var crypto = require('crypto');
7
- var https = require('https');
8
- var fs = require('fs');
9
- var path = require('path');
10
- var url = require('url');
11
5
  var AEntity_constants = require('@adaas/a-concept/dist/src/global/A-Entity/A-Entity.constants');
12
6
 
13
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
-
15
- var http__default = /*#__PURE__*/_interopDefault(http);
16
- var crypto__default = /*#__PURE__*/_interopDefault(crypto);
17
- var https__default = /*#__PURE__*/_interopDefault(https);
18
- var fs__default = /*#__PURE__*/_interopDefault(fs);
19
- var path__default = /*#__PURE__*/_interopDefault(path);
20
-
21
7
  var __defProp = Object.defineProperty;
22
8
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
23
9
  var __decorateClass = (decorators, target, key, kind) => {
@@ -272,13 +258,13 @@ var A_HTTPChannel = class extends aUtils.A_Channel {
272
258
  config
273
259
  });
274
260
  }
275
- buildURL(path2 = "", params = {}) {
261
+ buildURL(path = "", params = {}) {
276
262
  if (!this.baseUrl)
277
263
  throw new A_HTTPChannelError(
278
264
  A_HTTPChannelError.HttpRequestError,
279
265
  "Base URL is not set for HTTP Channel"
280
266
  );
281
- const url = new URL(`${this.baseUrl}${path2.startsWith("/") ? path2 : `/${path2}`}`);
267
+ const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
282
268
  Object.keys(params).forEach((key) => {
283
269
  if (params[key] !== void 0 && params[key] !== null) {
284
270
  url.searchParams.append(key, params[key]);
@@ -615,8 +601,148 @@ var A_Response = class extends aConcept.A_Entity {
615
601
  }, {});
616
602
  }
617
603
  };
604
+ var A_ServerLogger = class extends aUtils.A_Logger {
605
+ async onRequestEnd(request, response) {
606
+ this.route({
607
+ method: request.method,
608
+ url: request.url,
609
+ status: response.statusCode,
610
+ responseTime: response.duration
611
+ });
612
+ }
613
+ async onRequestError(request) {
614
+ }
615
+ logStart(container) {
616
+ this.serverReady({
617
+ port: container.port,
618
+ app: {
619
+ name: container.name
620
+ }
621
+ });
622
+ }
623
+ logStop(server) {
624
+ this.log("red", `Server ${server.name} stopped`);
625
+ }
626
+ metrics() {
627
+ }
628
+ routes(routes) {
629
+ const time = this.getTime();
630
+ console.log(`\x1B[36m[${this.scope.name}] |${time}| Exposed Routes:
631
+ ${" ".repeat(this.scopeLength + 3)}|-------------------------------
632
+ ${routes.map((route) => `${" ".repeat(this.scopeLength + 3)}| [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.path}`).join("\n")}
633
+ ${" ".repeat(this.scopeLength + 3)}|-------------------------------\x1B[0m`);
634
+ }
635
+ /**
636
+ * Logs the route information based on status code
637
+ *
638
+ * @param route
639
+ */
640
+ route(route) {
641
+ switch (route.status) {
642
+ case 200:
643
+ this.log200(route);
644
+ break;
645
+ case 404:
646
+ this.log404(route);
647
+ break;
648
+ case 500:
649
+ this.log500(route);
650
+ break;
651
+ case 400:
652
+ this.log400(route);
653
+ break;
654
+ default:
655
+ this.logDefault(route);
656
+ break;
657
+ }
658
+ }
659
+ log200(route) {
660
+ if (this.config.get("SERVER_IGNORE_LOG_200"))
661
+ return;
662
+ console.log(`\x1B[32m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
663
+ }
664
+ log404(route) {
665
+ if (this.config.get("SERVER_IGNORE_LOG_404"))
666
+ return;
667
+ console.log(`\x1B[33m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
668
+ }
669
+ log500(route) {
670
+ if (this.config.get("SERVER_IGNORE_LOG_500"))
671
+ return;
672
+ console.log(`\x1B[31m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
673
+ }
674
+ log400(route) {
675
+ if (this.config.get("SERVER_IGNORE_LOG_400"))
676
+ return;
677
+ console.log(`\x1B[33m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
678
+ }
679
+ logDefault(route) {
680
+ if (this.config.get("SERVER_IGNORE_LOG_DEFAULT"))
681
+ return;
682
+ console.log(`\x1B[36m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
683
+ }
684
+ serverReady(params) {
685
+ const processId = process.pid;
686
+ console.log(`\x1B[36m[${this.scope.name}] |${this.getTime()}| Server Ready:
687
+ ${" ".repeat(this.scopeLength + 3)}|-------------------------------
688
+ ${" ".repeat(this.scopeLength + 3)}| ${params.app.name} v${params.app.version || "0.0.1"} is running on port ${params.port}
689
+ ${" ".repeat(this.scopeLength + 3)}| Process ID: ${processId}
690
+ ${" ".repeat(this.scopeLength + 3)}|-------------------------------
691
+ ${" ".repeat(this.scopeLength + 3)}| ==============================
692
+ ${" ".repeat(this.scopeLength + 3)}| LISTENING...
693
+ ${" ".repeat(this.scopeLength + 3)}| ==============================
694
+ \x1B[0m`);
695
+ }
696
+ /**
697
+ * Displays a proxy routes
698
+ *
699
+ * @param params
700
+ */
701
+ proxy(params) {
702
+ console.log(`\x1B[35m[${this.scope.name}] |${this.getTime()}| Proxy:
703
+ ${" ".repeat(this.scopeLength + 3)}| ${params.original} -> ${params.destination}
704
+ ${" ".repeat(this.scopeLength + 3)}|-------------------------------\x1B[0m`);
705
+ }
706
+ };
707
+ __decorateClass([
708
+ aConcept.A_Feature.Extend({
709
+ name: "finish" /* Finish */,
710
+ scope: [A_Response]
711
+ }),
712
+ __decorateParam(0, aConcept.A_Inject(A_Request)),
713
+ __decorateParam(1, aConcept.A_Inject(A_Response))
714
+ ], A_ServerLogger.prototype, "onRequestEnd");
715
+ __decorateClass([
716
+ aConcept.A_Feature.Extend({
717
+ name: "error" /* Error */
718
+ }),
719
+ __decorateParam(0, aConcept.A_Inject(A_Request))
720
+ ], A_ServerLogger.prototype, "onRequestError");
721
+ __decorateClass([
722
+ aConcept.A_Feature.Extend({
723
+ name: "afterStart" /* afterStart */,
724
+ scope: [A_Service]
725
+ }),
726
+ __decorateParam(0, aConcept.A_Inject(A_Service))
727
+ ], A_ServerLogger.prototype, "logStart");
728
+ __decorateClass([
729
+ aConcept.A_Feature.Extend({
730
+ name: "afterStop" /* afterStop */,
731
+ scope: [A_Service]
732
+ }),
733
+ __decorateParam(0, aConcept.A_Inject(A_Server))
734
+ ], A_ServerLogger.prototype, "logStop");
735
+
736
+ // src/containers/A-Service/A-Service.container.ts
618
737
  var A_Service = class extends aConcept.A_Container {
619
738
  async load() {
739
+ if (!this.scope.has(A_ServerLogger))
740
+ this.scope.register(A_ServerLogger);
741
+ this.scope.resolve(A_ServerLogger);
742
+ let polyfill;
743
+ if (!this.scope.has(aUtils.A_Polyfill))
744
+ this.scope.register(aUtils.A_Polyfill);
745
+ polyfill = this.scope.resolve(aUtils.A_Polyfill);
620
746
  let config;
621
747
  if (!this.scope.has(aUtils.A_Config)) {
622
748
  const config2 = new aUtils.A_Config({
@@ -636,6 +762,7 @@ var A_Service = class extends aConcept.A_Container {
636
762
  });
637
763
  }
638
764
  this.port = config.get("A_SERVER_PORT");
765
+ const http = await polyfill.http();
639
766
  this.server = http.createServer(this.onRequest.bind(this));
640
767
  }
641
768
  listen() {
@@ -697,20 +824,20 @@ var A_Service = class extends aConcept.A_Container {
697
824
  }
698
825
  async convertToAServer(request, response) {
699
826
  if (!request.method || !request.url)
700
- throw new Error("Request method or url is missing");
701
- const id = this.generateRequestId(request.method, request.url);
827
+ throw new aConcept.A_Error("Request method or url is missing");
828
+ const id = await this.generateRequestId(request.method, request.url);
702
829
  const req = new A_Request({ id, request, scope: this.scope.name });
703
830
  const res = new A_Response({ id, response, scope: this.scope.name });
704
831
  await req.init();
705
832
  await res.init();
706
833
  return { req, res };
707
834
  }
708
- generateRequestId(method, url) {
709
- const hash = crypto__default.default.createHash("sha256");
835
+ async generateRequestId(method, url) {
836
+ const crypto = await this.scope.resolve(aUtils.A_Polyfill).crypto();
710
837
  const timeId = aConcept.A_IdentityHelper.generateTimeId();
711
838
  const randomValue = Math.random().toString();
712
- hash.update(`${timeId}-${method}-${url}-${randomValue}`);
713
- return `${timeId}-${hash.digest("hex")}`;
839
+ const hash = await crypto.createTextHash(`${timeId}-${method}-${url}-${randomValue}`, "sha256");
840
+ return `${timeId}-${hash}`;
714
841
  }
715
842
  async beforeStop() {
716
843
  }
@@ -771,13 +898,13 @@ var PROXY_CONFIG_DEFAULTS = {
771
898
  var A_ProxyConfig = class extends aConcept.A_Fragment {
772
899
  constructor(configs = {}) {
773
900
  super();
774
- this._configs = Object.entries(configs).map(([path2, config]) => {
901
+ this._configs = Object.entries(configs).map(([path, config]) => {
775
902
  const targetUrl = new URL(typeof config === "string" ? config : config.hostname || "");
776
903
  const port = targetUrl.port || (targetUrl.protocol === "https:" ? "443" : "80");
777
904
  const prepared = {
778
905
  ...PROXY_CONFIG_DEFAULTS,
779
906
  ...typeof config === "string" ? {
780
- path: path2,
907
+ path,
781
908
  port: parseInt(port),
782
909
  protocol: targetUrl.protocol,
783
910
  hostname: targetUrl.hostname
@@ -805,8 +932,8 @@ var A_ProxyConfig = class extends aConcept.A_Fragment {
805
932
  * @param path
806
933
  * @returns
807
934
  */
808
- has(path2) {
809
- return this._configs.some((route) => route.route.toRegExp().test(path2));
935
+ has(path) {
936
+ return this._configs.some((route) => route.route.toRegExp().test(path));
810
937
  }
811
938
  /**
812
939
  * Returns the proxy configuration for a given path, if exists
@@ -814,26 +941,170 @@ var A_ProxyConfig = class extends aConcept.A_Fragment {
814
941
  * @param path
815
942
  * @returns
816
943
  */
817
- config(path2) {
818
- return this._configs.find((route) => route.route.toRegExp().test(path2));
944
+ config(path) {
945
+ return this._configs.find((route) => route.route.toRegExp().test(path));
819
946
  }
820
947
  };
821
948
  var A_StaticConfig = class extends aConcept.A_Fragment {
822
- constructor(directories = []) {
949
+ constructor(directories = [], directoryConfigs = []) {
823
950
  super();
951
+ this._aliases = /* @__PURE__ */ new Map();
952
+ this._directoryConfigs = [];
824
953
  this.directories = directories;
954
+ this._directoryConfigs = directoryConfigs;
955
+ this.initializeDefaultAliases();
956
+ this.initializeCustomAliases();
957
+ }
958
+ initializeDefaultAliases() {
959
+ this.directories.forEach((dir, index) => {
960
+ const alias = {
961
+ alias: `/static${index > 0 ? index : ""}`,
962
+ path: `/static${index > 0 ? index : ""}`,
963
+ directory: dir,
964
+ enabled: true
965
+ };
966
+ this._aliases.set(alias.path, alias);
967
+ });
968
+ }
969
+ initializeCustomAliases() {
970
+ this._directoryConfigs.forEach((config) => {
971
+ const alias = {
972
+ alias: config.alias || config.path,
973
+ path: config.path,
974
+ directory: config.directory,
975
+ enabled: true
976
+ };
977
+ this._aliases.set(alias.path, alias);
978
+ });
825
979
  }
826
980
  /**
827
- * Checks if a given path is configured in the proxy
828
- *
981
+ * Add a custom static file alias
982
+ * @param alias - The URL path alias (e.g., '/assets')
983
+ * @param directory - The local directory path
984
+ * @param path - Optional custom path (defaults to alias)
985
+ */
986
+ addAlias(alias, directory, path) {
987
+ const staticAlias = {
988
+ alias,
989
+ path: path || alias,
990
+ directory,
991
+ enabled: true
992
+ };
993
+ this._aliases.set(staticAlias.path, staticAlias);
994
+ }
995
+ /**
996
+ * Remove a static file alias
997
+ * @param aliasPath - The path of the alias to remove
998
+ */
999
+ removeAlias(aliasPath) {
1000
+ return this._aliases.delete(aliasPath);
1001
+ }
1002
+ /**
1003
+ * Enable or disable an alias
1004
+ * @param aliasPath - The path of the alias
1005
+ * @param enabled - Whether to enable or disable
1006
+ */
1007
+ setAliasEnabled(aliasPath, enabled) {
1008
+ const alias = this._aliases.get(aliasPath);
1009
+ if (alias) {
1010
+ alias.enabled = enabled;
1011
+ return true;
1012
+ }
1013
+ return false;
1014
+ }
1015
+ /**
1016
+ * Get all configured aliases
1017
+ */
1018
+ getAliases() {
1019
+ return Array.from(this._aliases.values());
1020
+ }
1021
+ /**
1022
+ * Get enabled aliases only
1023
+ */
1024
+ getEnabledAliases() {
1025
+ return Array.from(this._aliases.values()).filter((alias) => alias.enabled !== false);
1026
+ }
1027
+ /**
1028
+ * Find the best matching alias for a given request path
1029
+ * @param requestPath - The request path to match
1030
+ */
1031
+ findMatchingAlias(requestPath) {
1032
+ let bestMatch = null;
1033
+ let longestMatch = 0;
1034
+ for (const alias of this.getEnabledAliases()) {
1035
+ if (requestPath.startsWith(alias.path) && alias.path.length > longestMatch) {
1036
+ bestMatch = alias;
1037
+ longestMatch = alias.path.length;
1038
+ }
1039
+ }
1040
+ return bestMatch;
1041
+ }
1042
+ /**
1043
+ * Check if an alias exists
1044
+ * @param aliasPath - The path to check
1045
+ */
1046
+ hasAlias(aliasPath) {
1047
+ return this._aliases.has(aliasPath);
1048
+ }
1049
+ /**
1050
+ * Get a specific alias by path
1051
+ * @param aliasPath - The path of the alias
1052
+ */
1053
+ getAlias(aliasPath) {
1054
+ return this._aliases.get(aliasPath);
1055
+ }
1056
+ /**
1057
+ * Add multiple aliases at once
1058
+ * @param aliases - Array of alias configurations
1059
+ */
1060
+ addAliases(aliases) {
1061
+ aliases.forEach((config) => {
1062
+ this.addAlias(config.alias || config.path, config.directory, config.path);
1063
+ });
1064
+ }
1065
+ /**
1066
+ * Clear all aliases
1067
+ */
1068
+ clearAliases() {
1069
+ this._aliases.clear();
1070
+ }
1071
+ /**
1072
+ * Update an existing alias
1073
+ * @param aliasPath - The path of the alias to update
1074
+ * @param updates - Partial updates to apply
1075
+ */
1076
+ updateAlias(aliasPath, updates) {
1077
+ const alias = this._aliases.get(aliasPath);
1078
+ if (alias) {
1079
+ Object.assign(alias, updates);
1080
+ return true;
1081
+ }
1082
+ return false;
1083
+ }
1084
+ /**
1085
+ * Get statistics about configured aliases
1086
+ */
1087
+ getStats() {
1088
+ const aliases = this.getAliases();
1089
+ const enabled = aliases.filter((a) => a.enabled !== false);
1090
+ const disabled = aliases.filter((a) => a.enabled === false);
1091
+ const directories = [...new Set(aliases.map((a) => a.directory))];
1092
+ return {
1093
+ total: aliases.length,
1094
+ enabled: enabled.length,
1095
+ disabled: disabled.length,
1096
+ directories
1097
+ };
1098
+ }
1099
+ /**
1100
+ * Checks if a given path is configured in the proxy (legacy method)
1101
+ * @deprecated Use findMatchingAlias instead
829
1102
  * @param path
830
1103
  * @returns
831
1104
  */
832
- has(path2) {
833
- const found = this.directories.find((dir) => {
834
- return new RegExp(`^/${dir.startsWith("/") ? dir.slice(1) : dir}/?.*`).test(path2);
835
- });
836
- return !!found && found;
1105
+ has(path) {
1106
+ const alias = this.findMatchingAlias(path);
1107
+ return alias ? alias.directory : false;
837
1108
  }
838
1109
  };
839
1110
  var A_ListQueryFilter = class extends aConcept.A_Fragment {
@@ -1005,137 +1276,6 @@ var A_EntityList = class extends aConcept.A_Entity {
1005
1276
  };
1006
1277
  }
1007
1278
  };
1008
- var A_ServerLogger = class extends aUtils.A_Logger {
1009
- async onRequestEnd(request, response) {
1010
- this.route({
1011
- method: request.method,
1012
- url: request.url,
1013
- status: response.statusCode,
1014
- responseTime: response.duration
1015
- });
1016
- }
1017
- async onRequestError(request) {
1018
- }
1019
- logStart(container) {
1020
- this.serverReady({
1021
- port: container.port,
1022
- app: {
1023
- name: container.name
1024
- }
1025
- });
1026
- }
1027
- logStop(server) {
1028
- this.log("red", `Server ${server.name} stopped`);
1029
- }
1030
- metrics() {
1031
- }
1032
- routes(routes) {
1033
- const time = this.getTime();
1034
- console.log(`\x1B[36m[${this.scope.name}] |${time}| Exposed Routes:
1035
- ${" ".repeat(this.scopeLength + 3)}|-------------------------------
1036
- ${routes.map((route) => `${" ".repeat(this.scopeLength + 3)}| [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.path}`).join("\n")}
1037
- ${" ".repeat(this.scopeLength + 3)}|-------------------------------\x1B[0m`);
1038
- }
1039
- /**
1040
- * Logs the route information based on status code
1041
- *
1042
- * @param route
1043
- */
1044
- route(route) {
1045
- switch (route.status) {
1046
- case 200:
1047
- this.log200(route);
1048
- break;
1049
- case 404:
1050
- this.log404(route);
1051
- break;
1052
- case 500:
1053
- this.log500(route);
1054
- break;
1055
- case 400:
1056
- this.log400(route);
1057
- break;
1058
- default:
1059
- this.logDefault(route);
1060
- break;
1061
- }
1062
- }
1063
- log200(route) {
1064
- if (this.config.get("SERVER_IGNORE_LOG_200"))
1065
- return;
1066
- console.log(`\x1B[32m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
1067
- }
1068
- log404(route) {
1069
- if (this.config.get("SERVER_IGNORE_LOG_404"))
1070
- return;
1071
- console.log(`\x1B[33m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
1072
- }
1073
- log500(route) {
1074
- if (this.config.get("SERVER_IGNORE_LOG_500"))
1075
- return;
1076
- console.log(`\x1B[31m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
1077
- }
1078
- log400(route) {
1079
- if (this.config.get("SERVER_IGNORE_LOG_400"))
1080
- return;
1081
- console.log(`\x1B[33m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
1082
- }
1083
- logDefault(route) {
1084
- if (this.config.get("SERVER_IGNORE_LOG_DEFAULT"))
1085
- return;
1086
- console.log(`\x1B[36m[${this.scope.name}] |${this.getTime()}| ${route.status} | [${route.method.toUpperCase()}]${" ".repeat(7 - route.method.length)} ${route.url} | ${route.responseTime}ms\x1B[0m`);
1087
- }
1088
- serverReady(params) {
1089
- const processId = process.pid;
1090
- console.log(`\x1B[36m[${this.scope.name}] |${this.getTime()}| Server Ready:
1091
- ${" ".repeat(this.scopeLength + 3)}|-------------------------------
1092
- ${" ".repeat(this.scopeLength + 3)}| ${params.app.name} v${params.app.version || "0.0.1"} is running on port ${params.port}
1093
- ${" ".repeat(this.scopeLength + 3)}| Process ID: ${processId}
1094
- ${" ".repeat(this.scopeLength + 3)}|-------------------------------
1095
- ${" ".repeat(this.scopeLength + 3)}| ==============================
1096
- ${" ".repeat(this.scopeLength + 3)}| LISTENING...
1097
- ${" ".repeat(this.scopeLength + 3)}| ==============================
1098
- \x1B[0m`);
1099
- }
1100
- /**
1101
- * Displays a proxy routes
1102
- *
1103
- * @param params
1104
- */
1105
- proxy(params) {
1106
- console.log(`\x1B[35m[${this.scope.name}] |${this.getTime()}| Proxy:
1107
- ${" ".repeat(this.scopeLength + 3)}| ${params.original} -> ${params.destination}
1108
- ${" ".repeat(this.scopeLength + 3)}|-------------------------------\x1B[0m`);
1109
- }
1110
- };
1111
- __decorateClass([
1112
- aConcept.A_Feature.Extend({
1113
- name: "finish" /* Finish */,
1114
- scope: [A_Response]
1115
- }),
1116
- __decorateParam(0, aConcept.A_Inject(A_Request)),
1117
- __decorateParam(1, aConcept.A_Inject(A_Response))
1118
- ], A_ServerLogger.prototype, "onRequestEnd");
1119
- __decorateClass([
1120
- aConcept.A_Feature.Extend({
1121
- name: "error" /* Error */
1122
- }),
1123
- __decorateParam(0, aConcept.A_Inject(A_Request))
1124
- ], A_ServerLogger.prototype, "onRequestError");
1125
- __decorateClass([
1126
- aConcept.A_Feature.Extend({
1127
- name: "afterStart" /* afterStart */,
1128
- scope: [A_Service]
1129
- }),
1130
- __decorateParam(0, aConcept.A_Inject(A_Service))
1131
- ], A_ServerLogger.prototype, "logStart");
1132
- __decorateClass([
1133
- aConcept.A_Feature.Extend({
1134
- name: "afterStop" /* afterStop */,
1135
- scope: [A_Service]
1136
- }),
1137
- __decorateParam(0, aConcept.A_Inject(A_Server))
1138
- ], A_ServerLogger.prototype, "logStop");
1139
1279
 
1140
1280
  // src/components/A-Router/A-Router.component.types.ts
1141
1281
  var A_SERVER_TYPES__RouterMethod = /* @__PURE__ */ ((A_SERVER_TYPES__RouterMethod2) => {
@@ -1161,12 +1301,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1161
1301
  * @param path
1162
1302
  * @returns
1163
1303
  */
1164
- static Post(path2) {
1304
+ static Post(path) {
1165
1305
  return this.defineRoute({
1166
1306
  method: "POST" /* POST */,
1167
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1168
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1169
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1307
+ path: typeof path === "object" && "path" in path ? path.path : path,
1308
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1309
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1170
1310
  });
1171
1311
  }
1172
1312
  /**
@@ -1175,12 +1315,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1175
1315
  * @param path
1176
1316
  * @returns
1177
1317
  */
1178
- static Get(path2) {
1318
+ static Get(path) {
1179
1319
  return this.defineRoute({
1180
1320
  method: "GET" /* GET */,
1181
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1182
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1183
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1321
+ path: typeof path === "object" && "path" in path ? path.path : path,
1322
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1323
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1184
1324
  });
1185
1325
  }
1186
1326
  /**
@@ -1189,12 +1329,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1189
1329
  * @param path
1190
1330
  * @returns
1191
1331
  */
1192
- static Put(path2) {
1332
+ static Put(path) {
1193
1333
  return this.defineRoute({
1194
1334
  method: "PUT" /* PUT */,
1195
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1196
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1197
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1335
+ path: typeof path === "object" && "path" in path ? path.path : path,
1336
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1337
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1198
1338
  });
1199
1339
  }
1200
1340
  /**
@@ -1203,12 +1343,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1203
1343
  * @param path
1204
1344
  * @returns
1205
1345
  */
1206
- static Delete(path2) {
1346
+ static Delete(path) {
1207
1347
  return this.defineRoute({
1208
1348
  method: "DELETE" /* DELETE */,
1209
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1210
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1211
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1349
+ path: typeof path === "object" && "path" in path ? path.path : path,
1350
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1351
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1212
1352
  });
1213
1353
  }
1214
1354
  /**
@@ -1217,12 +1357,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1217
1357
  * @param path
1218
1358
  * @returns
1219
1359
  */
1220
- static Patch(path2) {
1360
+ static Patch(path) {
1221
1361
  return this.defineRoute({
1222
1362
  method: "PATCH" /* PATCH */,
1223
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1224
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1225
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1363
+ path: typeof path === "object" && "path" in path ? path.path : path,
1364
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1365
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1226
1366
  });
1227
1367
  }
1228
1368
  /**
@@ -1231,12 +1371,12 @@ var _A_Router = class _A_Router extends aConcept.A_Component {
1231
1371
  * @param path
1232
1372
  * @returns
1233
1373
  */
1234
- static Default(path2) {
1374
+ static Default(path) {
1235
1375
  return this.defineRoute({
1236
1376
  method: "DEFAULT" /* DEFAULT */,
1237
- path: typeof path2 === "object" && "path" in path2 ? path2.path : path2,
1238
- version: typeof path2 === "object" && "version" in path2 && path2.version ? path2.version : "v1",
1239
- prefix: typeof path2 === "object" && "prefix" in path2 && path2.prefix ? path2.prefix : "api"
1377
+ path: typeof path === "object" && "path" in path ? path.path : path,
1378
+ version: typeof path === "object" && "version" in path && path.version ? path.version : "v1",
1379
+ prefix: typeof path === "object" && "prefix" in path && path.prefix ? path.prefix : "api"
1240
1380
  });
1241
1381
  }
1242
1382
  /**
@@ -1523,8 +1663,8 @@ var A_ServerProxy = class extends aConcept.A_Component {
1523
1663
  config.configs.map((c) => c.route).join("\n")
1524
1664
  );
1525
1665
  }
1526
- async onRequest(req, res, proxyConfig, logger) {
1527
- return new Promise((resolve, reject) => {
1666
+ async onRequest(req, res, proxyConfig, logger, polyfill) {
1667
+ return new Promise(async (resolve, reject) => {
1528
1668
  const { method, url } = req;
1529
1669
  const route = new A_Route(url, method);
1530
1670
  const config = proxyConfig.config(route.toString());
@@ -1536,7 +1676,7 @@ var A_ServerProxy = class extends aConcept.A_Component {
1536
1676
  `Proxying request ${method} ${url} to ${config.hostname}`,
1537
1677
  config
1538
1678
  );
1539
- const client = config.protocol === "https:" ? https__default.default : http__default.default;
1679
+ const client = await (config.protocol === "https:" ? polyfill.https() : polyfill.http());
1540
1680
  const proxyReq = client.request(
1541
1681
  {
1542
1682
  method: config.route.method,
@@ -1573,7 +1713,8 @@ __decorateClass([
1573
1713
  __decorateParam(0, aConcept.A_Inject(A_Request)),
1574
1714
  __decorateParam(1, aConcept.A_Inject(A_Response)),
1575
1715
  __decorateParam(2, aConcept.A_Inject(A_ProxyConfig)),
1576
- __decorateParam(3, aConcept.A_Inject(aUtils.A_Logger))
1716
+ __decorateParam(3, aConcept.A_Inject(aUtils.A_Logger)),
1717
+ __decorateParam(4, aConcept.A_Inject(aUtils.A_Polyfill))
1577
1718
  ], A_ServerProxy.prototype, "onRequest");
1578
1719
 
1579
1720
  // src/components/A-ServerCORS/A_ServerCORS.component.defaults.ts
@@ -1624,80 +1765,212 @@ __decorateClass([
1624
1765
  __decorateParam(1, aConcept.A_Inject(A_Response))
1625
1766
  ], A_ServerCORS.prototype, "apply");
1626
1767
  var A_StaticLoader = class extends aConcept.A_Component {
1627
- async load(logger, config) {
1768
+ async load(logger, config, polyfill) {
1769
+ this._fsPolyfill = await polyfill.fs();
1770
+ this._pathPolyfill = await polyfill.path();
1771
+ const aliases = config.getEnabledAliases();
1628
1772
  logger.log(
1629
1773
  "pink",
1630
- `Static directories configured:`,
1631
- config.directories.join("\n")
1774
+ `Static aliases configured:`,
1775
+ aliases.map((alias) => `${alias.alias} -> ${alias.directory}`).join("\n")
1632
1776
  );
1633
1777
  }
1634
- async onRequest(req, res, logger, config) {
1778
+ async onRequest(req, res, logger, config, polyfill) {
1635
1779
  if (req.method !== "GET" && req.method !== "HEAD") {
1636
1780
  return;
1637
1781
  }
1638
1782
  const { method, url } = req;
1639
1783
  const route = new A_Route(url, method);
1640
- const staticDirConfig = config.has(route.path);
1641
- if (!staticDirConfig) {
1784
+ const alias = config.findMatchingAlias(route.path);
1785
+ if (!alias) {
1642
1786
  return;
1643
1787
  }
1644
- const staticDir = path__default.default.resolve(process.cwd(), staticDirConfig);
1645
- if (!fs__default.default.existsSync(staticDir) || !fs__default.default.statSync(staticDir).isDirectory()) {
1646
- logger.log("red", `Static directory ${staticDir} does not exist or is not a directory.`);
1647
- return;
1788
+ try {
1789
+ const fs = this._fsPolyfill || await polyfill.fs();
1790
+ const path = this._pathPolyfill || await polyfill.path();
1791
+ const staticDir = path.resolve(process.cwd(), alias.directory);
1792
+ if (!fs.existsSync(staticDir)) {
1793
+ logger.log("red", `Static directory ${staticDir} does not exist.`);
1794
+ return;
1795
+ }
1796
+ const relativePath = route.path.replace(alias.path, "");
1797
+ const safePath = this.safeFilePath(staticDir, relativePath, req.headers?.host, path, fs);
1798
+ await this.serveFile(safePath, res, logger, fs, path);
1799
+ } catch (error) {
1800
+ logger.error(`Static file serving error: ${error.message}`);
1801
+ res.writeHead(404, { "Content-Type": "text/plain" });
1802
+ res.send("File not found");
1648
1803
  }
1649
- await this.serveFile(route.path.startsWith("/") ? route.path.slice(1) : route.path, res);
1804
+ }
1805
+ /**
1806
+ * Add a custom static file alias through the config
1807
+ * @param alias - The URL path alias (e.g., '/assets')
1808
+ * @param directory - The local directory path
1809
+ * @param path - Optional custom path (defaults to alias)
1810
+ * @param config - Static config instance
1811
+ * @param logger - Logger instance for logging
1812
+ */
1813
+ addAlias(alias, directory, config, logger, path) {
1814
+ config.addAlias(alias, directory, path);
1815
+ if (logger) {
1816
+ logger.log("cyan", `Static alias added: ${alias} -> ${directory}`);
1817
+ }
1818
+ }
1819
+ /**
1820
+ * Remove a static file alias through the config
1821
+ * @param aliasPath - The path of the alias to remove
1822
+ * @param config - Static config instance
1823
+ * @param logger - Logger instance for logging
1824
+ */
1825
+ removeAlias(aliasPath, config, logger) {
1826
+ const removed = config.removeAlias(aliasPath);
1827
+ if (removed && logger) {
1828
+ logger.log("yellow", `Static alias removed: ${aliasPath}`);
1829
+ }
1830
+ return removed;
1831
+ }
1832
+ /**
1833
+ * Get all configured aliases from config
1834
+ * @param config - Static config instance
1835
+ */
1836
+ getAliases(config) {
1837
+ return config.getAliases();
1838
+ }
1839
+ /**
1840
+ * Enable or disable an alias
1841
+ * @param aliasPath - The path of the alias
1842
+ * @param enabled - Whether to enable or disable
1843
+ * @param config - Static config instance
1844
+ * @param logger - Logger instance for logging
1845
+ */
1846
+ setAliasEnabled(aliasPath, enabled, config, logger) {
1847
+ const result = config.setAliasEnabled(aliasPath, enabled);
1848
+ if (result && logger) {
1849
+ logger.log("blue", `Static alias ${enabled ? "enabled" : "disabled"}: ${aliasPath}`);
1850
+ }
1851
+ return result;
1650
1852
  }
1651
1853
  getMimeType(ext) {
1652
1854
  const mimeTypes = {
1855
+ // Text
1653
1856
  ".html": "text/html",
1654
- ".js": "application/javascript",
1857
+ ".htm": "text/html",
1655
1858
  ".css": "text/css",
1859
+ ".txt": "text/plain",
1860
+ ".md": "text/markdown",
1861
+ ".xml": "application/xml",
1862
+ // JavaScript
1863
+ ".js": "application/javascript",
1864
+ ".mjs": "application/javascript",
1865
+ ".jsx": "application/javascript",
1866
+ ".ts": "application/typescript",
1867
+ ".tsx": "application/typescript",
1868
+ // JSON
1656
1869
  ".json": "application/json",
1870
+ ".jsonld": "application/ld+json",
1871
+ // Images
1657
1872
  ".png": "image/png",
1658
1873
  ".jpg": "image/jpeg",
1659
1874
  ".jpeg": "image/jpeg",
1660
1875
  ".gif": "image/gif",
1661
1876
  ".svg": "image/svg+xml",
1662
1877
  ".ico": "image/x-icon",
1663
- ".txt": "text/plain"
1878
+ ".webp": "image/webp",
1879
+ ".bmp": "image/bmp",
1880
+ ".tiff": "image/tiff",
1881
+ // Fonts
1882
+ ".woff": "font/woff",
1883
+ ".woff2": "font/woff2",
1884
+ ".ttf": "font/ttf",
1885
+ ".otf": "font/otf",
1886
+ ".eot": "application/vnd.ms-fontobject",
1887
+ // Audio/Video
1888
+ ".mp3": "audio/mpeg",
1889
+ ".wav": "audio/wav",
1890
+ ".mp4": "video/mp4",
1891
+ ".webm": "video/webm",
1892
+ ".ogg": "application/ogg",
1893
+ // Archives
1894
+ ".zip": "application/zip",
1895
+ ".tar": "application/x-tar",
1896
+ ".gz": "application/gzip",
1897
+ // Documents
1898
+ ".pdf": "application/pdf",
1899
+ ".doc": "application/msword",
1900
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1901
+ ".xls": "application/vnd.ms-excel",
1902
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1664
1903
  };
1665
1904
  return mimeTypes[ext.toLowerCase()] || "application/octet-stream";
1666
1905
  }
1667
- safeFilePath(staticDir, reqUrl, host) {
1668
- const parsedUrl = new url.URL(reqUrl || "/", `http://${host || "localhost"}`);
1906
+ safeFilePath(staticDir, reqUrl, host = "localhost", pathPolyfill, fsPolyfill) {
1907
+ const parsedUrl = new URL(reqUrl || "/", `http://${host}`);
1669
1908
  let pathname = decodeURIComponent(parsedUrl.pathname);
1670
1909
  pathname = pathname.replace(/\.\.[\/\\]/g, "");
1671
- let filePath = path__default.default.join(staticDir, pathname);
1672
- if (!fs__default.default.existsSync(filePath))
1910
+ let filePath = pathPolyfill.join(staticDir, pathname);
1911
+ if (!fsPolyfill.existsSync(filePath)) {
1673
1912
  throw new Error(`File not found: ${filePath}`);
1913
+ }
1674
1914
  return filePath;
1675
1915
  }
1676
- serveFile(filePath, res) {
1916
+ serveFile(filePath, res, logger, fsPolyfill, pathPolyfill) {
1677
1917
  return new Promise((resolve, reject) => {
1678
- if (fs__default.default.existsSync(filePath)) {
1679
- const ext = path__default.default.extname(filePath);
1680
- const contentType = this.getMimeType(ext);
1681
- res.writeHead(200, { "Content-Type": contentType });
1682
- const stream = fs__default.default.createReadStream(filePath);
1683
- stream.pipe(res.original);
1684
- stream.on("end", () => {
1685
- resolve();
1686
- });
1687
- stream.on("error", (err) => {
1688
- reject(new Error(`File stream error: ${err.message}`));
1689
- });
1690
- } else {
1691
- reject(new Error(`File not found: ${filePath}`));
1918
+ try {
1919
+ if (fsPolyfill.existsSync(filePath)) {
1920
+ const ext = pathPolyfill.extname(filePath);
1921
+ const contentType = this.getMimeType(ext);
1922
+ const headers = {
1923
+ "Content-Type": contentType,
1924
+ "Cache-Control": this.getCacheControl(ext),
1925
+ "X-Content-Type-Options": "nosniff"
1926
+ };
1927
+ res.writeHead(200, headers);
1928
+ const stream = fsPolyfill.createReadStream(filePath);
1929
+ if (stream && res.original) {
1930
+ stream.pipe(res.original);
1931
+ stream.on("end", () => {
1932
+ logger.log("green", `Successfully served: ${filePath}`);
1933
+ resolve();
1934
+ });
1935
+ stream.on("error", (err) => {
1936
+ logger.error(`File stream error: ${err.message}`);
1937
+ reject(new Error(`File stream error: ${err.message}`));
1938
+ });
1939
+ } else {
1940
+ res.writeHead(500, { "Content-Type": "text/plain" });
1941
+ res.send("Internal server error");
1942
+ reject(new Error("Failed to create file stream"));
1943
+ }
1944
+ } else {
1945
+ res.writeHead(404, { "Content-Type": "text/plain" });
1946
+ res.send("File not found");
1947
+ reject(new Error(`File not found: ${filePath}`));
1948
+ }
1949
+ } catch (error) {
1950
+ logger.error(`Error serving file: ${error.message}`);
1951
+ res.writeHead(500, { "Content-Type": "text/plain" });
1952
+ res.send("Internal server error");
1953
+ reject(error);
1692
1954
  }
1693
- resolve();
1694
1955
  });
1695
1956
  }
1957
+ getCacheControl(ext) {
1958
+ const staticAssets = [".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".otf"];
1959
+ const dynamicContent = [".html", ".htm"];
1960
+ if (staticAssets.includes(ext.toLowerCase())) {
1961
+ return "public, max-age=31536000";
1962
+ } else if (dynamicContent.includes(ext.toLowerCase())) {
1963
+ return "public, max-age=3600";
1964
+ } else {
1965
+ return "public, max-age=86400";
1966
+ }
1967
+ }
1696
1968
  };
1697
1969
  __decorateClass([
1698
1970
  aConcept.A_Concept.Load(),
1699
1971
  __decorateParam(0, aConcept.A_Inject(aUtils.A_Logger)),
1700
- __decorateParam(1, aConcept.A_Inject(A_StaticConfig))
1972
+ __decorateParam(1, aConcept.A_Inject(A_StaticConfig)),
1973
+ __decorateParam(2, aConcept.A_Inject(aUtils.A_Polyfill))
1701
1974
  ], A_StaticLoader.prototype, "load");
1702
1975
  __decorateClass([
1703
1976
  aConcept.A_Feature.Extend({
@@ -1706,7 +1979,8 @@ __decorateClass([
1706
1979
  __decorateParam(0, aConcept.A_Inject(A_Request)),
1707
1980
  __decorateParam(1, aConcept.A_Inject(A_Response)),
1708
1981
  __decorateParam(2, aConcept.A_Inject(aUtils.A_Logger)),
1709
- __decorateParam(3, aConcept.A_Inject(A_StaticConfig))
1982
+ __decorateParam(3, aConcept.A_Inject(A_StaticConfig)),
1983
+ __decorateParam(4, aConcept.A_Inject(aUtils.A_Polyfill))
1710
1984
  ], A_StaticLoader.prototype, "onRequest");
1711
1985
  var A_Controller = class extends aConcept.A_Component {
1712
1986
  async callEntityMethod(request, response, scope) {