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