@exyconn/common 2.1.0 → 2.3.2
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/README.md +864 -261
- package/dist/client/hooks/index.d.mts +1042 -0
- package/dist/client/hooks/index.d.ts +1042 -0
- package/dist/client/hooks/index.js +2276 -0
- package/dist/client/hooks/index.js.map +1 -0
- package/dist/client/hooks/index.mjs +2217 -0
- package/dist/client/hooks/index.mjs.map +1 -0
- package/dist/client/index.d.mts +3 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/web/index.d.mts +1461 -0
- package/dist/client/web/index.d.ts +1461 -0
- package/dist/client/web/index.js +2681 -0
- package/dist/client/web/index.js.map +1 -0
- package/dist/client/web/index.mjs +2618 -0
- package/dist/client/web/index.mjs.map +1 -0
- package/dist/data/brand-identity.d.mts +149 -0
- package/dist/data/brand-identity.d.ts +149 -0
- package/dist/data/brand-identity.js +235 -0
- package/dist/data/brand-identity.js.map +1 -0
- package/dist/data/brand-identity.mjs +220 -0
- package/dist/data/brand-identity.mjs.map +1 -0
- package/dist/data/countries.d.mts +61 -0
- package/dist/data/countries.d.ts +61 -0
- package/dist/data/countries.js +987 -0
- package/dist/data/countries.js.map +1 -0
- package/dist/data/countries.mjs +971 -0
- package/dist/data/countries.mjs.map +1 -0
- package/dist/data/currencies.d.mts +19 -0
- package/dist/data/currencies.d.ts +19 -0
- package/dist/data/currencies.js +162 -0
- package/dist/data/currencies.js.map +1 -0
- package/dist/data/currencies.mjs +153 -0
- package/dist/data/currencies.mjs.map +1 -0
- package/dist/data/index.d.mts +7 -0
- package/dist/data/index.d.ts +7 -0
- package/dist/data/index.js +2087 -0
- package/dist/data/index.js.map +1 -0
- package/dist/data/index.mjs +1948 -0
- package/dist/data/index.mjs.map +1 -0
- package/dist/data/phone-codes.d.mts +15 -0
- package/dist/data/phone-codes.d.ts +15 -0
- package/dist/data/phone-codes.js +219 -0
- package/dist/data/phone-codes.js.map +1 -0
- package/dist/data/phone-codes.mjs +211 -0
- package/dist/data/phone-codes.mjs.map +1 -0
- package/dist/data/regex.d.mts +287 -0
- package/dist/data/regex.d.ts +287 -0
- package/dist/data/regex.js +306 -0
- package/dist/data/regex.js.map +1 -0
- package/dist/data/regex.mjs +208 -0
- package/dist/data/regex.mjs.map +1 -0
- package/dist/data/timezones.d.mts +16 -0
- package/dist/data/timezones.d.ts +16 -0
- package/dist/data/timezones.js +98 -0
- package/dist/data/timezones.js.map +1 -0
- package/dist/data/timezones.mjs +89 -0
- package/dist/data/timezones.mjs.map +1 -0
- package/dist/index-01hoqibP.d.ts +119 -0
- package/dist/index-D3yCCjBZ.d.mts +119 -0
- package/dist/index-D9a9oxQy.d.ts +305 -0
- package/dist/index-DKn4raO7.d.ts +222 -0
- package/dist/index-DuxL84IW.d.mts +305 -0
- package/dist/index-NS8dS0p9.d.mts +222 -0
- package/dist/index-Nqm5_lwT.d.ts +188 -0
- package/dist/index-jBi3V6e5.d.mts +188 -0
- package/dist/index.d.mts +20 -579
- package/dist/index.d.ts +20 -579
- package/dist/index.js +717 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +716 -18
- package/dist/index.mjs.map +1 -1
- package/dist/server/configs/index.d.mts +602 -0
- package/dist/server/configs/index.d.ts +602 -0
- package/dist/server/configs/index.js +707 -0
- package/dist/server/configs/index.js.map +1 -0
- package/dist/server/configs/index.mjs +665 -0
- package/dist/server/configs/index.mjs.map +1 -0
- package/dist/server/index.d.mts +3 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +699 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +662 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/config/index.d.mts +40 -0
- package/dist/shared/config/index.d.ts +40 -0
- package/dist/shared/config/index.js +58 -0
- package/dist/shared/config/index.js.map +1 -0
- package/dist/shared/config/index.mjs +51 -0
- package/dist/shared/config/index.mjs.map +1 -0
- package/dist/shared/constants/index.d.mts +593 -0
- package/dist/shared/constants/index.d.ts +593 -0
- package/dist/shared/constants/index.js +391 -0
- package/dist/shared/constants/index.js.map +1 -0
- package/dist/shared/constants/index.mjs +360 -0
- package/dist/shared/constants/index.mjs.map +1 -0
- package/dist/shared/index.d.mts +5 -1
- package/dist/shared/index.d.ts +5 -1
- package/dist/shared/types/index.d.mts +140 -0
- package/dist/shared/types/index.d.ts +140 -0
- package/dist/shared/types/index.js +4 -0
- package/dist/shared/types/index.js.map +1 -0
- package/dist/shared/types/index.mjs +3 -0
- package/dist/shared/types/index.mjs.map +1 -0
- package/dist/shared/utils/index.d.mts +255 -0
- package/dist/shared/utils/index.d.ts +255 -0
- package/dist/shared/utils/index.js +623 -0
- package/dist/shared/utils/index.js.map +1 -0
- package/dist/shared/utils/index.mjs +324 -0
- package/dist/shared/utils/index.mjs.map +1 -0
- package/dist/shared/validation/index.d.mts +258 -0
- package/dist/shared/validation/index.d.ts +258 -0
- package/dist/shared/validation/index.js +185 -0
- package/dist/shared/validation/index.js.map +1 -0
- package/dist/shared/validation/index.mjs +172 -0
- package/dist/shared/validation/index.mjs.map +1 -0
- package/package.json +127 -62
- package/dist/index-BcxL4_V4.d.ts +0 -2946
- package/dist/index-DEzgM15j.d.ts +0 -67
- package/dist/index-DNFVgQx8.d.ts +0 -1375
- package/dist/index-DbV04Dx8.d.mts +0 -67
- package/dist/index-DfqEP6Oe.d.mts +0 -1375
- package/dist/index-bvvCev9Q.d.mts +0 -2946
package/dist/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import path, { resolve } from 'path';
|
|
|
4
4
|
import mongoose from 'mongoose';
|
|
5
5
|
import jwt from 'jsonwebtoken';
|
|
6
6
|
import { existsSync, readFileSync } from 'fs';
|
|
7
|
+
import rateLimit from 'express-rate-limit';
|
|
7
8
|
import axios from 'axios';
|
|
8
9
|
import { createContext, useState, useCallback, useMemo, useRef, useEffect, useContext } from 'react';
|
|
9
10
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -21,20 +22,50 @@ var __export = (target, all) => {
|
|
|
21
22
|
// src/server/index.ts
|
|
22
23
|
var server_exports = {};
|
|
23
24
|
__export(server_exports, {
|
|
25
|
+
ConfigBuilder: () => ConfigBuilder,
|
|
26
|
+
DEFAULT_AUTH_CONFIG: () => DEFAULT_AUTH_CONFIG,
|
|
27
|
+
DEFAULT_CORS_CONFIG: () => DEFAULT_CORS_CONFIG,
|
|
28
|
+
DEFAULT_CORS_ORIGINS: () => DEFAULT_CORS_ORIGINS,
|
|
29
|
+
DEFAULT_DATABASE_CONFIG: () => DEFAULT_DATABASE_CONFIG,
|
|
30
|
+
DEFAULT_LOGGING_CONFIG: () => DEFAULT_LOGGING_CONFIG,
|
|
31
|
+
DEFAULT_RATE_LIMIT_CONFIG: () => DEFAULT_RATE_LIMIT_CONFIG,
|
|
32
|
+
DEFAULT_RATE_LIMIT_TIERS: () => DEFAULT_RATE_LIMIT_TIERS,
|
|
33
|
+
DEFAULT_SERVER_CONFIG: () => DEFAULT_SERVER_CONFIG,
|
|
34
|
+
EXYCONN_CORS_CONFIG: () => EXYCONN_CORS_CONFIG,
|
|
35
|
+
PERMISSIVE_CORS_CONFIG: () => PERMISSIVE_CORS_CONFIG,
|
|
36
|
+
RATE_LIMIT_CONFIG: () => RATE_LIMIT_CONFIG,
|
|
37
|
+
RateLimiterBuilder: () => RateLimiterBuilder,
|
|
38
|
+
STRICT_CORS_CONFIG: () => STRICT_CORS_CONFIG,
|
|
24
39
|
StatusCode: () => StatusCode,
|
|
25
40
|
StatusMessage: () => StatusMessage,
|
|
26
41
|
authenticateApiKey: () => authenticateApiKey,
|
|
27
42
|
authenticateJWT: () => authenticateJWT,
|
|
28
43
|
badRequestResponse: () => badRequestResponse,
|
|
44
|
+
buildConfig: () => buildConfig,
|
|
29
45
|
buildFilter: () => buildFilter,
|
|
30
46
|
buildPagination: () => buildPagination,
|
|
31
47
|
buildPaginationMeta: () => buildPaginationMeta,
|
|
32
48
|
checkPackageServer: () => checkPackageServer,
|
|
33
49
|
conflictResponse: () => conflictResponse,
|
|
34
50
|
connectDB: () => connectDB,
|
|
51
|
+
corsOptions: () => corsOptions,
|
|
52
|
+
createApiKeyGenerator: () => createApiKeyGenerator,
|
|
53
|
+
createApiRateLimiter: () => createApiRateLimiter,
|
|
54
|
+
createBrandCorsOptions: () => createBrandCorsOptions,
|
|
55
|
+
createConfig: () => createConfig,
|
|
56
|
+
createCorsOptions: () => createCorsOptions,
|
|
57
|
+
createDdosRateLimiter: () => createDdosRateLimiter,
|
|
35
58
|
createLogger: () => createLogger,
|
|
36
59
|
createMorganStream: () => createMorganStream,
|
|
60
|
+
createMultiBrandCorsOptions: () => createMultiBrandCorsOptions,
|
|
61
|
+
createPrefixedKeyGenerator: () => createPrefixedKeyGenerator,
|
|
62
|
+
createRateLimiter: () => createRateLimiter,
|
|
63
|
+
createStandardRateLimiter: () => createStandardRateLimiter,
|
|
64
|
+
createStrictRateLimiter: () => createStrictRateLimiter,
|
|
65
|
+
createUserKeyGenerator: () => createUserKeyGenerator,
|
|
37
66
|
createdResponse: () => createdResponse,
|
|
67
|
+
ddosProtectionLimiter: () => ddosProtectionLimiter,
|
|
68
|
+
defaultKeyGenerator: () => defaultKeyGenerator,
|
|
38
69
|
disconnectDB: () => disconnectDB,
|
|
39
70
|
errorResponse: () => errorResponse,
|
|
40
71
|
extractColumns: () => extractColumns,
|
|
@@ -43,6 +74,10 @@ __export(server_exports, {
|
|
|
43
74
|
formatPackageCheckResult: () => formatPackageCheckResult,
|
|
44
75
|
generateNcuCommand: () => generateNcuCommand,
|
|
45
76
|
getConnectionStatus: () => getConnectionStatus,
|
|
77
|
+
getDatabaseOptions: () => getDatabaseOptions,
|
|
78
|
+
isDevelopment: () => isDevelopment,
|
|
79
|
+
isProduction: () => isProduction,
|
|
80
|
+
isTest: () => isTest,
|
|
46
81
|
logger: () => logger,
|
|
47
82
|
noContentResponse: () => noContentResponse,
|
|
48
83
|
notFoundResponse: () => notFoundResponse,
|
|
@@ -52,13 +87,16 @@ __export(server_exports, {
|
|
|
52
87
|
pickFields: () => pickFields,
|
|
53
88
|
printPackageCheckSummary: () => printPackageCheckSummary,
|
|
54
89
|
rateLimitResponse: () => rateLimitResponse,
|
|
90
|
+
rateLimiter: () => rateLimiter,
|
|
55
91
|
requireOrganization: () => requireOrganization,
|
|
56
92
|
sanitizeDocument: () => sanitizeDocument,
|
|
57
93
|
sanitizeUser: () => sanitizeUser,
|
|
58
94
|
simpleLogger: () => simpleLogger,
|
|
95
|
+
standardRateLimiter: () => standardRateLimiter,
|
|
59
96
|
statusCode: () => statusCode,
|
|
60
97
|
statusMessage: () => statusMessage,
|
|
61
98
|
stream: () => stream,
|
|
99
|
+
strictRateLimiter: () => strictRateLimiter,
|
|
62
100
|
successResponse: () => successResponse,
|
|
63
101
|
successResponseArr: () => successResponseArr,
|
|
64
102
|
unauthorizedResponse: () => unauthorizedResponse,
|
|
@@ -770,6 +808,666 @@ var packageCheckServer = {
|
|
|
770
808
|
print: printPackageCheckSummary
|
|
771
809
|
};
|
|
772
810
|
|
|
811
|
+
// src/server/configs/cors.config.ts
|
|
812
|
+
var DEFAULT_CORS_CONFIG = {
|
|
813
|
+
productionOrigins: [],
|
|
814
|
+
developmentOrigins: [
|
|
815
|
+
"http://localhost:3000",
|
|
816
|
+
"http://localhost:4000",
|
|
817
|
+
"http://localhost:5000",
|
|
818
|
+
"http://localhost:5173",
|
|
819
|
+
"http://localhost:8080",
|
|
820
|
+
"http://127.0.0.1:3000",
|
|
821
|
+
"http://127.0.0.1:4000",
|
|
822
|
+
"http://127.0.0.1:5000",
|
|
823
|
+
"http://127.0.0.1:5173",
|
|
824
|
+
"http://127.0.0.1:8080"
|
|
825
|
+
],
|
|
826
|
+
allowedSubdomains: [],
|
|
827
|
+
originPatterns: [],
|
|
828
|
+
allowNoOrigin: true,
|
|
829
|
+
allowAllInDev: true,
|
|
830
|
+
credentials: true,
|
|
831
|
+
methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"],
|
|
832
|
+
allowedHeaders: [
|
|
833
|
+
"Content-Type",
|
|
834
|
+
"Authorization",
|
|
835
|
+
"X-Requested-With",
|
|
836
|
+
"Accept",
|
|
837
|
+
"Origin",
|
|
838
|
+
"X-API-Key",
|
|
839
|
+
"X-Organization-Id",
|
|
840
|
+
"X-Request-Id"
|
|
841
|
+
],
|
|
842
|
+
exposedHeaders: [
|
|
843
|
+
"Content-Range",
|
|
844
|
+
"X-Content-Range",
|
|
845
|
+
"X-Total-Count",
|
|
846
|
+
"X-Request-Id"
|
|
847
|
+
],
|
|
848
|
+
maxAge: 86400
|
|
849
|
+
// 24 hours
|
|
850
|
+
};
|
|
851
|
+
var createCorsOptions = (config = {}) => {
|
|
852
|
+
const finalConfig = { ...DEFAULT_CORS_CONFIG, ...config };
|
|
853
|
+
const {
|
|
854
|
+
productionOrigins,
|
|
855
|
+
developmentOrigins,
|
|
856
|
+
allowedSubdomains,
|
|
857
|
+
originPatterns,
|
|
858
|
+
allowNoOrigin,
|
|
859
|
+
allowAllInDev,
|
|
860
|
+
customValidator,
|
|
861
|
+
credentials,
|
|
862
|
+
methods,
|
|
863
|
+
allowedHeaders,
|
|
864
|
+
exposedHeaders,
|
|
865
|
+
maxAge
|
|
866
|
+
} = finalConfig;
|
|
867
|
+
const allOrigins = /* @__PURE__ */ new Set([...productionOrigins, ...developmentOrigins]);
|
|
868
|
+
const originHandler = (origin, callback) => {
|
|
869
|
+
if (!origin) {
|
|
870
|
+
callback(null, allowNoOrigin);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (allOrigins.has(origin)) {
|
|
874
|
+
callback(null, true);
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
if (allowedSubdomains.some((subdomain) => origin.endsWith(subdomain))) {
|
|
878
|
+
callback(null, true);
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (originPatterns.some((pattern) => pattern.test(origin))) {
|
|
882
|
+
callback(null, true);
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (customValidator && customValidator(origin)) {
|
|
886
|
+
callback(null, true);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
if (process.env.NODE_ENV !== "production" && allowAllInDev) {
|
|
890
|
+
callback(null, true);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (process.env.NODE_ENV === "production") {
|
|
894
|
+
callback(new Error(`Origin ${origin} not allowed by CORS`));
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
callback(null, true);
|
|
898
|
+
};
|
|
899
|
+
return {
|
|
900
|
+
origin: originHandler,
|
|
901
|
+
credentials,
|
|
902
|
+
methods,
|
|
903
|
+
allowedHeaders,
|
|
904
|
+
exposedHeaders,
|
|
905
|
+
maxAge
|
|
906
|
+
};
|
|
907
|
+
};
|
|
908
|
+
var createBrandCorsOptions = (brandDomain, additionalConfig = {}) => {
|
|
909
|
+
const productionOrigins = [
|
|
910
|
+
`https://${brandDomain}`,
|
|
911
|
+
`https://www.${brandDomain}`
|
|
912
|
+
];
|
|
913
|
+
const allowedSubdomains = [`.${brandDomain}`];
|
|
914
|
+
return createCorsOptions({
|
|
915
|
+
productionOrigins,
|
|
916
|
+
allowedSubdomains,
|
|
917
|
+
...additionalConfig
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
var createMultiBrandCorsOptions = (domains, additionalConfig = {}) => {
|
|
921
|
+
const productionOrigins = domains.flatMap((domain) => [
|
|
922
|
+
`https://${domain}`,
|
|
923
|
+
`https://www.${domain}`
|
|
924
|
+
]);
|
|
925
|
+
const allowedSubdomains = domains.map((domain) => `.${domain}`);
|
|
926
|
+
return createCorsOptions({
|
|
927
|
+
productionOrigins,
|
|
928
|
+
allowedSubdomains,
|
|
929
|
+
...additionalConfig
|
|
930
|
+
});
|
|
931
|
+
};
|
|
932
|
+
var EXYCONN_CORS_CONFIG = {
|
|
933
|
+
productionOrigins: [
|
|
934
|
+
"https://exyconn.com",
|
|
935
|
+
"https://www.exyconn.com",
|
|
936
|
+
"https://botify.life",
|
|
937
|
+
"https://www.botify.life",
|
|
938
|
+
"https://partywings.fun",
|
|
939
|
+
"https://www.partywings.fun",
|
|
940
|
+
"https://sibera.work",
|
|
941
|
+
"https://www.sibera.work",
|
|
942
|
+
"https://spentiva.com",
|
|
943
|
+
"https://www.spentiva.com"
|
|
944
|
+
],
|
|
945
|
+
allowedSubdomains: [
|
|
946
|
+
".exyconn.com",
|
|
947
|
+
".botify.life",
|
|
948
|
+
".partywings.fun",
|
|
949
|
+
".sibera.work",
|
|
950
|
+
".spentiva.com"
|
|
951
|
+
],
|
|
952
|
+
developmentOrigins: [
|
|
953
|
+
"http://localhost:3000",
|
|
954
|
+
"http://localhost:4000",
|
|
955
|
+
"http://localhost:4001",
|
|
956
|
+
"http://localhost:4002",
|
|
957
|
+
"http://localhost:4003",
|
|
958
|
+
"http://localhost:4004",
|
|
959
|
+
"http://localhost:4005",
|
|
960
|
+
"http://localhost:5173",
|
|
961
|
+
"http://127.0.0.1:3000",
|
|
962
|
+
"http://127.0.0.1:4000",
|
|
963
|
+
"http://127.0.0.1:5173"
|
|
964
|
+
]
|
|
965
|
+
};
|
|
966
|
+
var STRICT_CORS_CONFIG = {
|
|
967
|
+
allowNoOrigin: false,
|
|
968
|
+
allowAllInDev: false,
|
|
969
|
+
methods: ["GET", "POST", "PUT", "DELETE"]
|
|
970
|
+
};
|
|
971
|
+
var PERMISSIVE_CORS_CONFIG = {
|
|
972
|
+
allowNoOrigin: true,
|
|
973
|
+
allowAllInDev: true,
|
|
974
|
+
originPatterns: [/localhost/, /127\.0\.0\.1/]
|
|
975
|
+
};
|
|
976
|
+
var corsOptions = createCorsOptions(EXYCONN_CORS_CONFIG);
|
|
977
|
+
var DEFAULT_RATE_LIMIT_TIERS = {
|
|
978
|
+
STANDARD: {
|
|
979
|
+
windowMs: 15 * 60 * 1e3,
|
|
980
|
+
// 15 minutes
|
|
981
|
+
maxRequests: 100,
|
|
982
|
+
message: "Too many requests, please try again later.",
|
|
983
|
+
skipSuccessfulRequests: false,
|
|
984
|
+
skipFailedRequests: false
|
|
985
|
+
},
|
|
986
|
+
STRICT: {
|
|
987
|
+
windowMs: 15 * 60 * 1e3,
|
|
988
|
+
// 15 minutes
|
|
989
|
+
maxRequests: 20,
|
|
990
|
+
message: "Too many requests, please try again later.",
|
|
991
|
+
skipSuccessfulRequests: false,
|
|
992
|
+
skipFailedRequests: false
|
|
993
|
+
},
|
|
994
|
+
DDOS: {
|
|
995
|
+
windowMs: 60 * 1e3,
|
|
996
|
+
// 1 minute
|
|
997
|
+
maxRequests: 60,
|
|
998
|
+
message: "Rate limit exceeded. Please slow down.",
|
|
999
|
+
skipSuccessfulRequests: false,
|
|
1000
|
+
skipFailedRequests: false
|
|
1001
|
+
},
|
|
1002
|
+
// Additional presets
|
|
1003
|
+
VERY_STRICT: {
|
|
1004
|
+
windowMs: 60 * 60 * 1e3,
|
|
1005
|
+
// 1 hour
|
|
1006
|
+
maxRequests: 5,
|
|
1007
|
+
message: "Too many attempts. Please try again in an hour.",
|
|
1008
|
+
skipSuccessfulRequests: false,
|
|
1009
|
+
skipFailedRequests: false
|
|
1010
|
+
},
|
|
1011
|
+
RELAXED: {
|
|
1012
|
+
windowMs: 15 * 60 * 1e3,
|
|
1013
|
+
// 15 minutes
|
|
1014
|
+
maxRequests: 500,
|
|
1015
|
+
message: "Rate limit exceeded.",
|
|
1016
|
+
skipSuccessfulRequests: false,
|
|
1017
|
+
skipFailedRequests: false
|
|
1018
|
+
},
|
|
1019
|
+
API: {
|
|
1020
|
+
windowMs: 60 * 1e3,
|
|
1021
|
+
// 1 minute
|
|
1022
|
+
maxRequests: 30,
|
|
1023
|
+
message: "API rate limit exceeded.",
|
|
1024
|
+
skipSuccessfulRequests: false,
|
|
1025
|
+
skipFailedRequests: false
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
var defaultKeyGenerator = (req) => {
|
|
1029
|
+
const forwarded = req.headers["x-forwarded-for"];
|
|
1030
|
+
const ip = forwarded ? Array.isArray(forwarded) ? forwarded[0] : forwarded.split(",")[0].trim() : req.ip || req.socket.remoteAddress || "unknown";
|
|
1031
|
+
return ip;
|
|
1032
|
+
};
|
|
1033
|
+
var createPrefixedKeyGenerator = (prefix) => (req) => {
|
|
1034
|
+
return `${prefix}:${defaultKeyGenerator(req)}`;
|
|
1035
|
+
};
|
|
1036
|
+
var createUserKeyGenerator = (getUserId) => (req) => {
|
|
1037
|
+
const userId = getUserId(req);
|
|
1038
|
+
return userId || defaultKeyGenerator(req);
|
|
1039
|
+
};
|
|
1040
|
+
var createApiKeyGenerator = (headerName = "x-api-key") => (req) => {
|
|
1041
|
+
const apiKey = req.headers[headerName.toLowerCase()];
|
|
1042
|
+
return apiKey || defaultKeyGenerator(req);
|
|
1043
|
+
};
|
|
1044
|
+
var createRateLimitResponse = (message, retryAfter) => ({
|
|
1045
|
+
status: "error",
|
|
1046
|
+
statusCode: 429,
|
|
1047
|
+
message,
|
|
1048
|
+
...retryAfter
|
|
1049
|
+
});
|
|
1050
|
+
var createRateLimiter = (tierConfig, options = {}) => {
|
|
1051
|
+
const {
|
|
1052
|
+
standardHeaders = true,
|
|
1053
|
+
legacyHeaders = false,
|
|
1054
|
+
keyGenerator = defaultKeyGenerator,
|
|
1055
|
+
skip,
|
|
1056
|
+
handler
|
|
1057
|
+
} = options;
|
|
1058
|
+
return rateLimit({
|
|
1059
|
+
windowMs: tierConfig.windowMs,
|
|
1060
|
+
max: tierConfig.maxRequests,
|
|
1061
|
+
message: createRateLimitResponse(tierConfig.message),
|
|
1062
|
+
standardHeaders,
|
|
1063
|
+
legacyHeaders,
|
|
1064
|
+
keyGenerator,
|
|
1065
|
+
skip,
|
|
1066
|
+
handler,
|
|
1067
|
+
skipSuccessfulRequests: tierConfig.skipSuccessfulRequests,
|
|
1068
|
+
skipFailedRequests: tierConfig.skipFailedRequests
|
|
1069
|
+
});
|
|
1070
|
+
};
|
|
1071
|
+
var createStandardRateLimiter = (config = {}, options = {}) => {
|
|
1072
|
+
const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STANDARD, ...config };
|
|
1073
|
+
return createRateLimiter(tierConfig, options);
|
|
1074
|
+
};
|
|
1075
|
+
var createStrictRateLimiter = (config = {}, options = {}) => {
|
|
1076
|
+
const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.STRICT, ...config };
|
|
1077
|
+
return createRateLimiter(tierConfig, options);
|
|
1078
|
+
};
|
|
1079
|
+
var createDdosRateLimiter = (config = {}, options = {}) => {
|
|
1080
|
+
const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.DDOS, ...config };
|
|
1081
|
+
return createRateLimiter(tierConfig, options);
|
|
1082
|
+
};
|
|
1083
|
+
var createApiRateLimiter = (config = {}, options = {}) => {
|
|
1084
|
+
const tierConfig = { ...DEFAULT_RATE_LIMIT_TIERS.API, ...config };
|
|
1085
|
+
return createRateLimiter(tierConfig, {
|
|
1086
|
+
keyGenerator: createApiKeyGenerator(),
|
|
1087
|
+
...options
|
|
1088
|
+
});
|
|
1089
|
+
};
|
|
1090
|
+
var RateLimiterBuilder = class {
|
|
1091
|
+
constructor(preset = "STANDARD") {
|
|
1092
|
+
const presetConfig = DEFAULT_RATE_LIMIT_TIERS[preset];
|
|
1093
|
+
this.config = {
|
|
1094
|
+
windowMs: presetConfig.windowMs,
|
|
1095
|
+
maxRequests: presetConfig.maxRequests,
|
|
1096
|
+
message: presetConfig.message,
|
|
1097
|
+
skipSuccessfulRequests: presetConfig.skipSuccessfulRequests ?? false,
|
|
1098
|
+
skipFailedRequests: presetConfig.skipFailedRequests ?? false
|
|
1099
|
+
};
|
|
1100
|
+
this.options = {};
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Set window duration
|
|
1104
|
+
*/
|
|
1105
|
+
windowMs(ms) {
|
|
1106
|
+
this.config.windowMs = ms;
|
|
1107
|
+
return this;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Set window duration in minutes
|
|
1111
|
+
*/
|
|
1112
|
+
windowMinutes(minutes) {
|
|
1113
|
+
this.config.windowMs = minutes * 60 * 1e3;
|
|
1114
|
+
return this;
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Set window duration in hours
|
|
1118
|
+
*/
|
|
1119
|
+
windowHours(hours) {
|
|
1120
|
+
this.config.windowMs = hours * 60 * 60 * 1e3;
|
|
1121
|
+
return this;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Set maximum requests
|
|
1125
|
+
*/
|
|
1126
|
+
max(requests) {
|
|
1127
|
+
this.config.maxRequests = requests;
|
|
1128
|
+
return this;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Set error message
|
|
1132
|
+
*/
|
|
1133
|
+
message(msg) {
|
|
1134
|
+
this.config.message = msg;
|
|
1135
|
+
return this;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Skip successful requests
|
|
1139
|
+
*/
|
|
1140
|
+
skipSuccessful(skip = true) {
|
|
1141
|
+
this.config.skipSuccessfulRequests = skip;
|
|
1142
|
+
return this;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Skip failed requests
|
|
1146
|
+
*/
|
|
1147
|
+
skipFailed(skip = true) {
|
|
1148
|
+
this.config.skipFailedRequests = skip;
|
|
1149
|
+
return this;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Set key generator
|
|
1153
|
+
*/
|
|
1154
|
+
keyBy(generator) {
|
|
1155
|
+
this.options.keyGenerator = generator;
|
|
1156
|
+
return this;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Key by IP (default)
|
|
1160
|
+
*/
|
|
1161
|
+
keyByIp() {
|
|
1162
|
+
this.options.keyGenerator = defaultKeyGenerator;
|
|
1163
|
+
return this;
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Key by API key
|
|
1167
|
+
*/
|
|
1168
|
+
keyByApiKey(headerName) {
|
|
1169
|
+
this.options.keyGenerator = createApiKeyGenerator(headerName);
|
|
1170
|
+
return this;
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Skip certain requests
|
|
1174
|
+
*/
|
|
1175
|
+
skipWhen(predicate) {
|
|
1176
|
+
this.options.skip = predicate;
|
|
1177
|
+
return this;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Build the rate limiter
|
|
1181
|
+
*/
|
|
1182
|
+
build() {
|
|
1183
|
+
return createRateLimiter(this.config, this.options);
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
var rateLimiter = (preset) => {
|
|
1187
|
+
return new RateLimiterBuilder(preset);
|
|
1188
|
+
};
|
|
1189
|
+
var RATE_LIMIT_CONFIG = {
|
|
1190
|
+
STANDARD: DEFAULT_RATE_LIMIT_TIERS.STANDARD,
|
|
1191
|
+
STRICT: DEFAULT_RATE_LIMIT_TIERS.STRICT,
|
|
1192
|
+
DDOS: DEFAULT_RATE_LIMIT_TIERS.DDOS
|
|
1193
|
+
};
|
|
1194
|
+
var standardRateLimiter = createStandardRateLimiter();
|
|
1195
|
+
var strictRateLimiter = createStrictRateLimiter();
|
|
1196
|
+
var ddosProtectionLimiter = createDdosRateLimiter();
|
|
1197
|
+
|
|
1198
|
+
// src/server/configs/server.config.ts
|
|
1199
|
+
var DEFAULT_SERVER_CONFIG = {
|
|
1200
|
+
name: "app-server",
|
|
1201
|
+
version: "1.0.0",
|
|
1202
|
+
environment: process.env.NODE_ENV || "development",
|
|
1203
|
+
port: parseInt(process.env.PORT || "3000", 10),
|
|
1204
|
+
host: process.env.HOST || "0.0.0.0",
|
|
1205
|
+
basePath: "/api",
|
|
1206
|
+
debug: process.env.DEBUG === "true",
|
|
1207
|
+
trustProxy: true
|
|
1208
|
+
};
|
|
1209
|
+
var DEFAULT_DATABASE_CONFIG = {
|
|
1210
|
+
uri: process.env.DATABASE_URL || process.env.MONGODB_URI || "",
|
|
1211
|
+
name: process.env.DATABASE_NAME || "app_db",
|
|
1212
|
+
maxPoolSize: process.env.NODE_ENV === "production" ? 50 : 10,
|
|
1213
|
+
minPoolSize: process.env.NODE_ENV === "production" ? 10 : 5,
|
|
1214
|
+
socketTimeoutMS: 45e3,
|
|
1215
|
+
serverSelectionTimeoutMS: 1e4,
|
|
1216
|
+
maxIdleTimeMS: 1e4,
|
|
1217
|
+
retryWrites: true,
|
|
1218
|
+
retryReads: true,
|
|
1219
|
+
writeConcern: "majority"
|
|
1220
|
+
};
|
|
1221
|
+
var DEFAULT_AUTH_CONFIG = {
|
|
1222
|
+
jwtSecret: process.env.JWT_SECRET || "",
|
|
1223
|
+
jwtExpiresIn: process.env.JWT_EXPIRES_IN || "7d",
|
|
1224
|
+
refreshTokenExpiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || "30d",
|
|
1225
|
+
enableRefreshTokens: true,
|
|
1226
|
+
apiKeyHeader: "x-api-key",
|
|
1227
|
+
orgHeader: "x-organization-id"
|
|
1228
|
+
};
|
|
1229
|
+
var DEFAULT_LOGGING_CONFIG = {
|
|
1230
|
+
level: process.env.LOG_LEVEL || "info",
|
|
1231
|
+
logsDir: process.env.LOGS_DIR || "logs",
|
|
1232
|
+
maxSize: "20m",
|
|
1233
|
+
maxFiles: "14d",
|
|
1234
|
+
errorMaxFiles: "30d",
|
|
1235
|
+
console: true,
|
|
1236
|
+
file: process.env.NODE_ENV === "production",
|
|
1237
|
+
json: process.env.NODE_ENV === "production"
|
|
1238
|
+
};
|
|
1239
|
+
var DEFAULT_CORS_ORIGINS = {
|
|
1240
|
+
production: [],
|
|
1241
|
+
development: [
|
|
1242
|
+
"http://localhost:3000",
|
|
1243
|
+
"http://localhost:4000",
|
|
1244
|
+
"http://localhost:5173",
|
|
1245
|
+
"http://127.0.0.1:3000",
|
|
1246
|
+
"http://127.0.0.1:4000",
|
|
1247
|
+
"http://127.0.0.1:5173"
|
|
1248
|
+
],
|
|
1249
|
+
patterns: []
|
|
1250
|
+
};
|
|
1251
|
+
var DEFAULT_RATE_LIMIT_CONFIG = {
|
|
1252
|
+
enabled: true,
|
|
1253
|
+
standard: {
|
|
1254
|
+
windowMs: 15 * 60 * 1e3,
|
|
1255
|
+
// 15 minutes
|
|
1256
|
+
maxRequests: 100,
|
|
1257
|
+
message: "Too many requests, please try again later."
|
|
1258
|
+
},
|
|
1259
|
+
strict: {
|
|
1260
|
+
windowMs: 15 * 60 * 1e3,
|
|
1261
|
+
// 15 minutes
|
|
1262
|
+
maxRequests: 20,
|
|
1263
|
+
message: "Too many requests, please try again later."
|
|
1264
|
+
},
|
|
1265
|
+
ddos: {
|
|
1266
|
+
windowMs: 60 * 1e3,
|
|
1267
|
+
// 1 minute
|
|
1268
|
+
maxRequests: 60,
|
|
1269
|
+
message: "Rate limit exceeded. Please slow down.",
|
|
1270
|
+
skipSuccessfulRequests: false
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
function deepMerge(target, source) {
|
|
1274
|
+
const result = { ...target };
|
|
1275
|
+
for (const key in source) {
|
|
1276
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
1277
|
+
const sourceValue = source[key];
|
|
1278
|
+
const targetValue = target[key];
|
|
1279
|
+
if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
|
|
1280
|
+
result[key] = deepMerge(
|
|
1281
|
+
targetValue,
|
|
1282
|
+
sourceValue
|
|
1283
|
+
);
|
|
1284
|
+
} else if (sourceValue !== void 0) {
|
|
1285
|
+
result[key] = sourceValue;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return result;
|
|
1290
|
+
}
|
|
1291
|
+
var ConfigBuilder = class {
|
|
1292
|
+
constructor() {
|
|
1293
|
+
this.config = {
|
|
1294
|
+
server: { ...DEFAULT_SERVER_CONFIG },
|
|
1295
|
+
database: { ...DEFAULT_DATABASE_CONFIG },
|
|
1296
|
+
auth: { ...DEFAULT_AUTH_CONFIG },
|
|
1297
|
+
logging: { ...DEFAULT_LOGGING_CONFIG },
|
|
1298
|
+
cors: { ...DEFAULT_CORS_ORIGINS },
|
|
1299
|
+
rateLimit: { ...DEFAULT_RATE_LIMIT_CONFIG }
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Set server configuration
|
|
1304
|
+
*/
|
|
1305
|
+
setServer(config) {
|
|
1306
|
+
this.config.server = deepMerge(this.config.server, config);
|
|
1307
|
+
return this;
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Set database configuration
|
|
1311
|
+
*/
|
|
1312
|
+
setDatabase(config) {
|
|
1313
|
+
this.config.database = deepMerge(this.config.database, config);
|
|
1314
|
+
return this;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Set auth configuration
|
|
1318
|
+
*/
|
|
1319
|
+
setAuth(config) {
|
|
1320
|
+
this.config.auth = deepMerge(this.config.auth, config);
|
|
1321
|
+
return this;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Set logging configuration
|
|
1325
|
+
*/
|
|
1326
|
+
setLogging(config) {
|
|
1327
|
+
this.config.logging = deepMerge(this.config.logging, config);
|
|
1328
|
+
return this;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Set CORS origins
|
|
1332
|
+
*/
|
|
1333
|
+
setCorsOrigins(config) {
|
|
1334
|
+
this.config.cors = deepMerge(this.config.cors, config);
|
|
1335
|
+
return this;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Add CORS production origin
|
|
1339
|
+
*/
|
|
1340
|
+
addProductionOrigin(origin) {
|
|
1341
|
+
if (!this.config.cors.production.includes(origin)) {
|
|
1342
|
+
this.config.cors.production.push(origin);
|
|
1343
|
+
}
|
|
1344
|
+
return this;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Add CORS development origin
|
|
1348
|
+
*/
|
|
1349
|
+
addDevelopmentOrigin(origin) {
|
|
1350
|
+
if (!this.config.cors.development.includes(origin)) {
|
|
1351
|
+
this.config.cors.development.push(origin);
|
|
1352
|
+
}
|
|
1353
|
+
return this;
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Add CORS pattern
|
|
1357
|
+
*/
|
|
1358
|
+
addCorsPattern(pattern) {
|
|
1359
|
+
if (!this.config.cors.patterns.includes(pattern)) {
|
|
1360
|
+
this.config.cors.patterns.push(pattern);
|
|
1361
|
+
}
|
|
1362
|
+
return this;
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Set rate limit configuration
|
|
1366
|
+
*/
|
|
1367
|
+
setRateLimit(config) {
|
|
1368
|
+
this.config.rateLimit = deepMerge(this.config.rateLimit, config);
|
|
1369
|
+
return this;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Add custom rate limit tier
|
|
1373
|
+
*/
|
|
1374
|
+
addRateLimitTier(name, tier) {
|
|
1375
|
+
if (!this.config.rateLimit.custom) {
|
|
1376
|
+
this.config.rateLimit.custom = {};
|
|
1377
|
+
}
|
|
1378
|
+
this.config.rateLimit.custom[name] = tier;
|
|
1379
|
+
return this;
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Set custom configuration
|
|
1383
|
+
*/
|
|
1384
|
+
setCustom(key, value) {
|
|
1385
|
+
if (!this.config.custom) {
|
|
1386
|
+
this.config.custom = {};
|
|
1387
|
+
}
|
|
1388
|
+
this.config.custom[key] = value;
|
|
1389
|
+
return this;
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Load configuration from environment variables
|
|
1393
|
+
*/
|
|
1394
|
+
loadFromEnv() {
|
|
1395
|
+
if (process.env.SERVER_NAME) this.config.server.name = process.env.SERVER_NAME;
|
|
1396
|
+
if (process.env.SERVER_VERSION) this.config.server.version = process.env.SERVER_VERSION;
|
|
1397
|
+
if (process.env.PORT) this.config.server.port = parseInt(process.env.PORT, 10);
|
|
1398
|
+
if (process.env.HOST) this.config.server.host = process.env.HOST;
|
|
1399
|
+
if (process.env.BASE_PATH) this.config.server.basePath = process.env.BASE_PATH;
|
|
1400
|
+
if (process.env.DATABASE_URL) this.config.database.uri = process.env.DATABASE_URL;
|
|
1401
|
+
if (process.env.MONGODB_URI) this.config.database.uri = process.env.MONGODB_URI;
|
|
1402
|
+
if (process.env.DATABASE_NAME) this.config.database.name = process.env.DATABASE_NAME;
|
|
1403
|
+
if (process.env.JWT_SECRET) this.config.auth.jwtSecret = process.env.JWT_SECRET;
|
|
1404
|
+
if (process.env.JWT_EXPIRES_IN) this.config.auth.jwtExpiresIn = process.env.JWT_EXPIRES_IN;
|
|
1405
|
+
if (process.env.LOG_LEVEL) this.config.logging.level = process.env.LOG_LEVEL;
|
|
1406
|
+
if (process.env.LOGS_DIR) this.config.logging.logsDir = process.env.LOGS_DIR;
|
|
1407
|
+
if (process.env.CORS_ORIGINS) {
|
|
1408
|
+
const origins = process.env.CORS_ORIGINS.split(",").map((o) => o.trim());
|
|
1409
|
+
this.config.cors.production.push(...origins);
|
|
1410
|
+
}
|
|
1411
|
+
return this;
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Validate configuration
|
|
1415
|
+
*/
|
|
1416
|
+
validate() {
|
|
1417
|
+
const errors = [];
|
|
1418
|
+
if (!this.config.server.name) errors.push("Server name is required");
|
|
1419
|
+
if (this.config.server.port < 1 || this.config.server.port > 65535) {
|
|
1420
|
+
errors.push("Server port must be between 1 and 65535");
|
|
1421
|
+
}
|
|
1422
|
+
if (this.config.server.environment === "production") {
|
|
1423
|
+
if (!this.config.auth.jwtSecret || this.config.auth.jwtSecret.length < 32) {
|
|
1424
|
+
errors.push("JWT secret must be at least 32 characters in production");
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return { valid: errors.length === 0, errors };
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Build the final configuration
|
|
1431
|
+
*/
|
|
1432
|
+
build() {
|
|
1433
|
+
return { ...this.config };
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
var createConfig = () => {
|
|
1437
|
+
return new ConfigBuilder();
|
|
1438
|
+
};
|
|
1439
|
+
var buildConfig = (partial = {}) => {
|
|
1440
|
+
const builder = createConfig().loadFromEnv();
|
|
1441
|
+
if (partial.server) builder.setServer(partial.server);
|
|
1442
|
+
if (partial.database) builder.setDatabase(partial.database);
|
|
1443
|
+
if (partial.auth) builder.setAuth(partial.auth);
|
|
1444
|
+
if (partial.logging) builder.setLogging(partial.logging);
|
|
1445
|
+
if (partial.cors) builder.setCorsOrigins(partial.cors);
|
|
1446
|
+
if (partial.rateLimit) builder.setRateLimit(partial.rateLimit);
|
|
1447
|
+
return builder.build();
|
|
1448
|
+
};
|
|
1449
|
+
var isProduction = (config) => {
|
|
1450
|
+
return (config?.environment || process.env.NODE_ENV) === "production";
|
|
1451
|
+
};
|
|
1452
|
+
var isDevelopment = (config) => {
|
|
1453
|
+
return (config?.environment || process.env.NODE_ENV) === "development";
|
|
1454
|
+
};
|
|
1455
|
+
var isTest = (config) => {
|
|
1456
|
+
return (config?.environment || process.env.NODE_ENV) === "test";
|
|
1457
|
+
};
|
|
1458
|
+
var getDatabaseOptions = (config) => {
|
|
1459
|
+
return {
|
|
1460
|
+
maxPoolSize: config.maxPoolSize,
|
|
1461
|
+
minPoolSize: config.minPoolSize,
|
|
1462
|
+
socketTimeoutMS: config.socketTimeoutMS,
|
|
1463
|
+
serverSelectionTimeoutMS: config.serverSelectionTimeoutMS,
|
|
1464
|
+
maxIdleTimeMS: config.maxIdleTimeMS,
|
|
1465
|
+
retryWrites: config.retryWrites,
|
|
1466
|
+
retryReads: config.retryReads,
|
|
1467
|
+
w: config.writeConcern
|
|
1468
|
+
};
|
|
1469
|
+
};
|
|
1470
|
+
|
|
773
1471
|
// src/client/index.ts
|
|
774
1472
|
var client_exports = {};
|
|
775
1473
|
__export(client_exports, {
|
|
@@ -806,7 +1504,7 @@ __export(client_exports, {
|
|
|
806
1504
|
createTheme: () => createTheme,
|
|
807
1505
|
createThemeFromBrand: () => createThemeFromBrand,
|
|
808
1506
|
cssVar: () => cssVar,
|
|
809
|
-
deepMerge: () =>
|
|
1507
|
+
deepMerge: () => deepMerge2,
|
|
810
1508
|
defaultDarkTheme: () => defaultDarkTheme,
|
|
811
1509
|
defaultLightTheme: () => defaultLightTheme,
|
|
812
1510
|
dummyBannerData: () => dummyBannerData,
|
|
@@ -4943,14 +5641,14 @@ var defaultDarkTheme = {
|
|
|
4943
5641
|
};
|
|
4944
5642
|
|
|
4945
5643
|
// src/client/web/theme/theme-utils.ts
|
|
4946
|
-
function
|
|
5644
|
+
function deepMerge2(target, source) {
|
|
4947
5645
|
const output = { ...target };
|
|
4948
5646
|
for (const key in source) {
|
|
4949
5647
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
4950
5648
|
const sourceValue = source[key];
|
|
4951
5649
|
const targetValue = target[key];
|
|
4952
5650
|
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
4953
|
-
output[key] =
|
|
5651
|
+
output[key] = deepMerge2(
|
|
4954
5652
|
targetValue,
|
|
4955
5653
|
sourceValue
|
|
4956
5654
|
);
|
|
@@ -5016,7 +5714,7 @@ function createThemeFromBrand(brand, baseTheme = defaultLightTheme) {
|
|
|
5016
5714
|
}
|
|
5017
5715
|
}
|
|
5018
5716
|
};
|
|
5019
|
-
return
|
|
5717
|
+
return deepMerge2(baseTheme, brandOverrides);
|
|
5020
5718
|
}
|
|
5021
5719
|
function adjustColor(hex, percent) {
|
|
5022
5720
|
hex = hex.replace(/^#/, "");
|
|
@@ -5110,8 +5808,8 @@ async function createTheme(config = {}) {
|
|
|
5110
5808
|
if (config.themeUrl) {
|
|
5111
5809
|
const urlTheme = await loadThemeFromUrl(config.themeUrl);
|
|
5112
5810
|
if (urlTheme) {
|
|
5113
|
-
lightTheme =
|
|
5114
|
-
darkTheme =
|
|
5811
|
+
lightTheme = deepMerge2(lightTheme, urlTheme);
|
|
5812
|
+
darkTheme = deepMerge2(darkTheme, urlTheme);
|
|
5115
5813
|
}
|
|
5116
5814
|
}
|
|
5117
5815
|
if (config.brandIdentity) {
|
|
@@ -5119,10 +5817,10 @@ async function createTheme(config = {}) {
|
|
|
5119
5817
|
darkTheme = createThemeFromBrand(config.brandIdentity, darkTheme);
|
|
5120
5818
|
}
|
|
5121
5819
|
if (config.light) {
|
|
5122
|
-
lightTheme =
|
|
5820
|
+
lightTheme = deepMerge2(lightTheme, config.light);
|
|
5123
5821
|
}
|
|
5124
5822
|
if (config.dark) {
|
|
5125
|
-
darkTheme =
|
|
5823
|
+
darkTheme = deepMerge2(darkTheme, config.dark);
|
|
5126
5824
|
}
|
|
5127
5825
|
return { light: lightTheme, dark: darkTheme };
|
|
5128
5826
|
}
|
|
@@ -5196,7 +5894,7 @@ function ThemeProvider({
|
|
|
5196
5894
|
theme2 = createThemeFromBrand(brandIdentity, theme2);
|
|
5197
5895
|
}
|
|
5198
5896
|
if (lightOverrides) {
|
|
5199
|
-
theme2 =
|
|
5897
|
+
theme2 = deepMerge2(theme2, lightOverrides);
|
|
5200
5898
|
}
|
|
5201
5899
|
return theme2;
|
|
5202
5900
|
});
|
|
@@ -5207,7 +5905,7 @@ function ThemeProvider({
|
|
|
5207
5905
|
theme2 = createThemeFromBrand(brandIdentity, theme2);
|
|
5208
5906
|
}
|
|
5209
5907
|
if (darkOverrides) {
|
|
5210
|
-
theme2 =
|
|
5908
|
+
theme2 = deepMerge2(theme2, darkOverrides);
|
|
5211
5909
|
}
|
|
5212
5910
|
return theme2;
|
|
5213
5911
|
});
|
|
@@ -5226,8 +5924,8 @@ function ThemeProvider({
|
|
|
5226
5924
|
setError(null);
|
|
5227
5925
|
loadThemeFromUrl(themeUrl).then((urlTheme) => {
|
|
5228
5926
|
if (urlTheme) {
|
|
5229
|
-
setLightTheme((prev) =>
|
|
5230
|
-
setDarkTheme((prev) =>
|
|
5927
|
+
setLightTheme((prev) => deepMerge2(prev, urlTheme));
|
|
5928
|
+
setDarkTheme((prev) => deepMerge2(prev, urlTheme));
|
|
5231
5929
|
}
|
|
5232
5930
|
}).catch((err) => {
|
|
5233
5931
|
setError(err instanceof Error ? err.message : "Failed to load theme");
|
|
@@ -5272,8 +5970,8 @@ function ThemeProvider({
|
|
|
5272
5970
|
});
|
|
5273
5971
|
}, []);
|
|
5274
5972
|
const updateTheme = useCallback((updates) => {
|
|
5275
|
-
setLightTheme((prev) =>
|
|
5276
|
-
setDarkTheme((prev) =>
|
|
5973
|
+
setLightTheme((prev) => deepMerge2(prev, updates));
|
|
5974
|
+
setDarkTheme((prev) => deepMerge2(prev, updates));
|
|
5277
5975
|
}, []);
|
|
5278
5976
|
const resetTheme = useCallback(() => {
|
|
5279
5977
|
let light = defaultLightTheme;
|
|
@@ -5283,10 +5981,10 @@ function ThemeProvider({
|
|
|
5283
5981
|
dark = createThemeFromBrand(brandIdentity, dark);
|
|
5284
5982
|
}
|
|
5285
5983
|
if (lightOverrides) {
|
|
5286
|
-
light =
|
|
5984
|
+
light = deepMerge2(light, lightOverrides);
|
|
5287
5985
|
}
|
|
5288
5986
|
if (darkOverrides) {
|
|
5289
|
-
dark =
|
|
5987
|
+
dark = deepMerge2(dark, darkOverrides);
|
|
5290
5988
|
}
|
|
5291
5989
|
setLightTheme(light);
|
|
5292
5990
|
setDarkTheme(dark);
|
|
@@ -6641,7 +7339,7 @@ __export(shared_exports, {
|
|
|
6641
7339
|
isSameMonth: () => isSameMonth,
|
|
6642
7340
|
isSameWeek: () => isSameWeek,
|
|
6643
7341
|
isSameYear: () => isSameYear,
|
|
6644
|
-
isTest: () =>
|
|
7342
|
+
isTest: () => isTest2,
|
|
6645
7343
|
isThisMonth: () => isThisMonth,
|
|
6646
7344
|
isThisWeek: () => isThisWeek,
|
|
6647
7345
|
isThisYear: () => isThisYear,
|
|
@@ -6720,7 +7418,7 @@ var isProd = () => {
|
|
|
6720
7418
|
var isDev = () => {
|
|
6721
7419
|
return process.env.NODE_ENV === "development";
|
|
6722
7420
|
};
|
|
6723
|
-
var
|
|
7421
|
+
var isTest2 = () => {
|
|
6724
7422
|
return process.env.NODE_ENV === "test";
|
|
6725
7423
|
};
|
|
6726
7424
|
var validateEnv = (requiredVars) => {
|