@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.d.mts +126 -10
- package/dist/index.d.ts +126 -10
- package/dist/index.js +504 -230
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +507 -225
- package/dist/index.mjs.map +1 -1
- package/examples/simple-server/concept.ts +8 -1
- package/package.json +2 -2
- package/src/components/A-ServerProxy/A-ServerProxy.component.ts +8 -7
- package/src/components/A-StaticLoader/A-StaticLoader.component.ts +220 -49
- package/src/components/A-StaticLoader/A-StaticLoader.component.types.ts +5 -107
- package/src/containers/A-Service/A-Service.container.ts +38 -18
- package/src/context/A-StaticConfig/A-StaticConfig.context.ts +192 -9
- package/src/entities/A-Request/A-Request.entity.ts +1 -1
- package/src/entities/A-Request/A-Request.entity.types.ts +1 -1
- package/src/entities/A-Response/A-Response.entity.ts +1 -1
- package/src/entities/A-Response/A-Response.entity.types.ts +1 -1
- package/tsconfig.build.json +0 -28
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A_Config, A_Logger, A_Channel, A_Manifest } from '@adaas/a-utils';
|
|
3
|
-
import http, { createServer } from 'http';
|
|
4
|
-
import crypto from 'crypto';
|
|
5
|
-
import https from 'https';
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { URL as URL$1 } from 'url';
|
|
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
|
+
import { A_Polyfill, A_Config, A_Logger, A_Channel, A_Manifest } from '@adaas/a-utils';
|
|
9
3
|
import { A_TYPES__EntityFeatures } from '@adaas/a-concept/dist/src/global/A-Entity/A-Entity.constants';
|
|
10
4
|
|
|
11
5
|
var __defProp = Object.defineProperty;
|
|
@@ -262,13 +256,13 @@ var A_HTTPChannel = class extends A_Channel {
|
|
|
262
256
|
config
|
|
263
257
|
});
|
|
264
258
|
}
|
|
265
|
-
buildURL(
|
|
259
|
+
buildURL(path = "", params = {}) {
|
|
266
260
|
if (!this.baseUrl)
|
|
267
261
|
throw new A_HTTPChannelError(
|
|
268
262
|
A_HTTPChannelError.HttpRequestError,
|
|
269
263
|
"Base URL is not set for HTTP Channel"
|
|
270
264
|
);
|
|
271
|
-
const url = new URL(`${this.baseUrl}${
|
|
265
|
+
const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
272
266
|
Object.keys(params).forEach((key) => {
|
|
273
267
|
if (params[key] !== void 0 && params[key] !== null) {
|
|
274
268
|
url.searchParams.append(key, params[key]);
|
|
@@ -605,8 +599,148 @@ var A_Response = class extends A_Entity {
|
|
|
605
599
|
}, {});
|
|
606
600
|
}
|
|
607
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
|
|
608
735
|
var A_Service = class extends A_Container {
|
|
609
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);
|
|
610
744
|
let config;
|
|
611
745
|
if (!this.scope.has(A_Config)) {
|
|
612
746
|
const config2 = new A_Config({
|
|
@@ -626,7 +760,8 @@ var A_Service = class extends A_Container {
|
|
|
626
760
|
});
|
|
627
761
|
}
|
|
628
762
|
this.port = config.get("A_SERVER_PORT");
|
|
629
|
-
|
|
763
|
+
const http = await polyfill.http();
|
|
764
|
+
this.server = http.createServer(this.onRequest.bind(this));
|
|
630
765
|
}
|
|
631
766
|
listen() {
|
|
632
767
|
return new Promise((resolve, reject) => {
|
|
@@ -687,20 +822,20 @@ var A_Service = class extends A_Container {
|
|
|
687
822
|
}
|
|
688
823
|
async convertToAServer(request, response) {
|
|
689
824
|
if (!request.method || !request.url)
|
|
690
|
-
throw new
|
|
691
|
-
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);
|
|
692
827
|
const req = new A_Request({ id, request, scope: this.scope.name });
|
|
693
828
|
const res = new A_Response({ id, response, scope: this.scope.name });
|
|
694
829
|
await req.init();
|
|
695
830
|
await res.init();
|
|
696
831
|
return { req, res };
|
|
697
832
|
}
|
|
698
|
-
generateRequestId(method, url) {
|
|
699
|
-
const
|
|
833
|
+
async generateRequestId(method, url) {
|
|
834
|
+
const crypto = await this.scope.resolve(A_Polyfill).crypto();
|
|
700
835
|
const timeId = A_IdentityHelper.generateTimeId();
|
|
701
836
|
const randomValue = Math.random().toString();
|
|
702
|
-
hash.
|
|
703
|
-
return `${timeId}-${hash
|
|
837
|
+
const hash = await crypto.createTextHash(`${timeId}-${method}-${url}-${randomValue}`, "sha256");
|
|
838
|
+
return `${timeId}-${hash}`;
|
|
704
839
|
}
|
|
705
840
|
async beforeStop() {
|
|
706
841
|
}
|
|
@@ -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(([
|
|
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
|
|
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(
|
|
799
|
-
return this._configs.some((route) => route.route.toRegExp().test(
|
|
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(
|
|
808
|
-
return this._configs.find((route) => route.route.toRegExp().test(
|
|
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
|
-
*
|
|
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(
|
|
823
|
-
const
|
|
824
|
-
|
|
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(
|
|
1302
|
+
static Post(path) {
|
|
1155
1303
|
return this.defineRoute({
|
|
1156
1304
|
method: "POST" /* POST */,
|
|
1157
|
-
path: typeof
|
|
1158
|
-
version: typeof
|
|
1159
|
-
prefix: typeof
|
|
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(
|
|
1316
|
+
static Get(path) {
|
|
1169
1317
|
return this.defineRoute({
|
|
1170
1318
|
method: "GET" /* GET */,
|
|
1171
|
-
path: typeof
|
|
1172
|
-
version: typeof
|
|
1173
|
-
prefix: typeof
|
|
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(
|
|
1330
|
+
static Put(path) {
|
|
1183
1331
|
return this.defineRoute({
|
|
1184
1332
|
method: "PUT" /* PUT */,
|
|
1185
|
-
path: typeof
|
|
1186
|
-
version: typeof
|
|
1187
|
-
prefix: typeof
|
|
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(
|
|
1344
|
+
static Delete(path) {
|
|
1197
1345
|
return this.defineRoute({
|
|
1198
1346
|
method: "DELETE" /* DELETE */,
|
|
1199
|
-
path: typeof
|
|
1200
|
-
version: typeof
|
|
1201
|
-
prefix: typeof
|
|
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(
|
|
1358
|
+
static Patch(path) {
|
|
1211
1359
|
return this.defineRoute({
|
|
1212
1360
|
method: "PATCH" /* PATCH */,
|
|
1213
|
-
path: typeof
|
|
1214
|
-
version: typeof
|
|
1215
|
-
prefix: typeof
|
|
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(
|
|
1372
|
+
static Default(path) {
|
|
1225
1373
|
return this.defineRoute({
|
|
1226
1374
|
method: "DEFAULT" /* DEFAULT */,
|
|
1227
|
-
path: typeof
|
|
1228
|
-
version: typeof
|
|
1229
|
-
prefix: typeof
|
|
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
|
/**
|
|
@@ -1513,8 +1661,8 @@ var A_ServerProxy = class extends A_Component {
|
|
|
1513
1661
|
config.configs.map((c) => c.route).join("\n")
|
|
1514
1662
|
);
|
|
1515
1663
|
}
|
|
1516
|
-
async onRequest(req, res, proxyConfig, logger) {
|
|
1517
|
-
return new Promise((resolve, reject) => {
|
|
1664
|
+
async onRequest(req, res, proxyConfig, logger, polyfill) {
|
|
1665
|
+
return new Promise(async (resolve, reject) => {
|
|
1518
1666
|
const { method, url } = req;
|
|
1519
1667
|
const route = new A_Route(url, method);
|
|
1520
1668
|
const config = proxyConfig.config(route.toString());
|
|
@@ -1526,7 +1674,7 @@ var A_ServerProxy = class extends A_Component {
|
|
|
1526
1674
|
`Proxying request ${method} ${url} to ${config.hostname}`,
|
|
1527
1675
|
config
|
|
1528
1676
|
);
|
|
1529
|
-
const client = config.protocol === "https:" ? https : http;
|
|
1677
|
+
const client = await (config.protocol === "https:" ? polyfill.https() : polyfill.http());
|
|
1530
1678
|
const proxyReq = client.request(
|
|
1531
1679
|
{
|
|
1532
1680
|
method: config.route.method,
|
|
@@ -1563,7 +1711,8 @@ __decorateClass([
|
|
|
1563
1711
|
__decorateParam(0, A_Inject(A_Request)),
|
|
1564
1712
|
__decorateParam(1, A_Inject(A_Response)),
|
|
1565
1713
|
__decorateParam(2, A_Inject(A_ProxyConfig)),
|
|
1566
|
-
__decorateParam(3, A_Inject(A_Logger))
|
|
1714
|
+
__decorateParam(3, A_Inject(A_Logger)),
|
|
1715
|
+
__decorateParam(4, A_Inject(A_Polyfill))
|
|
1567
1716
|
], A_ServerProxy.prototype, "onRequest");
|
|
1568
1717
|
|
|
1569
1718
|
// src/components/A-ServerCORS/A_ServerCORS.component.defaults.ts
|
|
@@ -1614,80 +1763,212 @@ __decorateClass([
|
|
|
1614
1763
|
__decorateParam(1, A_Inject(A_Response))
|
|
1615
1764
|
], A_ServerCORS.prototype, "apply");
|
|
1616
1765
|
var A_StaticLoader = class extends A_Component {
|
|
1617
|
-
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();
|
|
1618
1770
|
logger.log(
|
|
1619
1771
|
"pink",
|
|
1620
|
-
`Static
|
|
1621
|
-
|
|
1772
|
+
`Static aliases configured:`,
|
|
1773
|
+
aliases.map((alias) => `${alias.alias} -> ${alias.directory}`).join("\n")
|
|
1622
1774
|
);
|
|
1623
1775
|
}
|
|
1624
|
-
async onRequest(req, res, logger, config) {
|
|
1776
|
+
async onRequest(req, res, logger, config, polyfill) {
|
|
1625
1777
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
1626
1778
|
return;
|
|
1627
1779
|
}
|
|
1628
1780
|
const { method, url } = req;
|
|
1629
1781
|
const route = new A_Route(url, method);
|
|
1630
|
-
const
|
|
1631
|
-
if (!
|
|
1782
|
+
const alias = config.findMatchingAlias(route.path);
|
|
1783
|
+
if (!alias) {
|
|
1632
1784
|
return;
|
|
1633
1785
|
}
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
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");
|
|
1638
1801
|
}
|
|
1639
|
-
|
|
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;
|
|
1640
1850
|
}
|
|
1641
1851
|
getMimeType(ext) {
|
|
1642
1852
|
const mimeTypes = {
|
|
1853
|
+
// Text
|
|
1643
1854
|
".html": "text/html",
|
|
1644
|
-
".
|
|
1855
|
+
".htm": "text/html",
|
|
1645
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
|
|
1646
1867
|
".json": "application/json",
|
|
1868
|
+
".jsonld": "application/ld+json",
|
|
1869
|
+
// Images
|
|
1647
1870
|
".png": "image/png",
|
|
1648
1871
|
".jpg": "image/jpeg",
|
|
1649
1872
|
".jpeg": "image/jpeg",
|
|
1650
1873
|
".gif": "image/gif",
|
|
1651
1874
|
".svg": "image/svg+xml",
|
|
1652
1875
|
".ico": "image/x-icon",
|
|
1653
|
-
".
|
|
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"
|
|
1654
1901
|
};
|
|
1655
1902
|
return mimeTypes[ext.toLowerCase()] || "application/octet-stream";
|
|
1656
1903
|
}
|
|
1657
|
-
safeFilePath(staticDir, reqUrl, host) {
|
|
1658
|
-
const parsedUrl = new URL
|
|
1904
|
+
safeFilePath(staticDir, reqUrl, host = "localhost", pathPolyfill, fsPolyfill) {
|
|
1905
|
+
const parsedUrl = new URL(reqUrl || "/", `http://${host}`);
|
|
1659
1906
|
let pathname = decodeURIComponent(parsedUrl.pathname);
|
|
1660
1907
|
pathname = pathname.replace(/\.\.[\/\\]/g, "");
|
|
1661
|
-
let filePath =
|
|
1662
|
-
if (!
|
|
1908
|
+
let filePath = pathPolyfill.join(staticDir, pathname);
|
|
1909
|
+
if (!fsPolyfill.existsSync(filePath)) {
|
|
1663
1910
|
throw new Error(`File not found: ${filePath}`);
|
|
1911
|
+
}
|
|
1664
1912
|
return filePath;
|
|
1665
1913
|
}
|
|
1666
|
-
serveFile(filePath, res) {
|
|
1914
|
+
serveFile(filePath, res, logger, fsPolyfill, pathPolyfill) {
|
|
1667
1915
|
return new Promise((resolve, reject) => {
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
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);
|
|
1682
1952
|
}
|
|
1683
|
-
resolve();
|
|
1684
1953
|
});
|
|
1685
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
|
+
}
|
|
1686
1966
|
};
|
|
1687
1967
|
__decorateClass([
|
|
1688
1968
|
A_Concept.Load(),
|
|
1689
1969
|
__decorateParam(0, A_Inject(A_Logger)),
|
|
1690
|
-
__decorateParam(1, A_Inject(A_StaticConfig))
|
|
1970
|
+
__decorateParam(1, A_Inject(A_StaticConfig)),
|
|
1971
|
+
__decorateParam(2, A_Inject(A_Polyfill))
|
|
1691
1972
|
], A_StaticLoader.prototype, "load");
|
|
1692
1973
|
__decorateClass([
|
|
1693
1974
|
A_Feature.Extend({
|
|
@@ -1696,7 +1977,8 @@ __decorateClass([
|
|
|
1696
1977
|
__decorateParam(0, A_Inject(A_Request)),
|
|
1697
1978
|
__decorateParam(1, A_Inject(A_Response)),
|
|
1698
1979
|
__decorateParam(2, A_Inject(A_Logger)),
|
|
1699
|
-
__decorateParam(3, A_Inject(A_StaticConfig))
|
|
1980
|
+
__decorateParam(3, A_Inject(A_StaticConfig)),
|
|
1981
|
+
__decorateParam(4, A_Inject(A_Polyfill))
|
|
1700
1982
|
], A_StaticLoader.prototype, "onRequest");
|
|
1701
1983
|
var A_Controller = class extends A_Component {
|
|
1702
1984
|
async callEntityMethod(request, response, scope) {
|