tezx 2.0.11 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +122 -89
  2. package/bun/getConnInfo.d.ts +21 -0
  3. package/bun/getConnInfo.js +9 -0
  4. package/bun/index.d.ts +10 -4
  5. package/bun/index.js +8 -4
  6. package/bun/ws.d.ts +48 -0
  7. package/bun/ws.js +58 -0
  8. package/cjs/bun/getConnInfo.js +12 -0
  9. package/cjs/bun/index.js +35 -7
  10. package/cjs/bun/ws.js +63 -0
  11. package/cjs/core/config.js +2 -12
  12. package/cjs/core/context.js +131 -379
  13. package/cjs/core/error.js +49 -0
  14. package/cjs/core/request.js +79 -131
  15. package/cjs/core/router.js +54 -387
  16. package/cjs/core/server.js +83 -202
  17. package/cjs/deno/env.js +4 -4
  18. package/cjs/deno/getConnInfo.js +18 -0
  19. package/cjs/deno/index.js +11 -18
  20. package/cjs/deno/serveStatic.js +53 -0
  21. package/cjs/deno/ws.js +39 -0
  22. package/cjs/helper/index.js +46 -10
  23. package/cjs/index.js +5 -7
  24. package/cjs/jwt/node.js +94 -0
  25. package/cjs/jwt/web.js +178 -0
  26. package/cjs/middleware/basic-auth.js +42 -0
  27. package/cjs/middleware/bearer-auth.js +34 -0
  28. package/cjs/middleware/cache-control.js +44 -0
  29. package/cjs/middleware/cors.js +11 -21
  30. package/cjs/middleware/detect-bot.js +57 -0
  31. package/cjs/middleware/i18n.js +73 -60
  32. package/cjs/middleware/index.js +8 -46
  33. package/cjs/middleware/logger.js +9 -4
  34. package/cjs/middleware/pagination.js +3 -2
  35. package/cjs/middleware/powered-by.js +3 -2
  36. package/cjs/middleware/rate-limiter.js +38 -0
  37. package/cjs/middleware/request-id.js +4 -5
  38. package/cjs/middleware/sanitize-headers.js +22 -0
  39. package/cjs/middleware/secure-headers copy.js +143 -0
  40. package/cjs/middleware/secure-headers.js +157 -0
  41. package/cjs/middleware/{xssProtection.js → xss-protection.js} +5 -8
  42. package/cjs/node/env.js +7 -7
  43. package/cjs/node/getConnInfo.js +16 -0
  44. package/cjs/node/index.js +17 -18
  45. package/cjs/node/mount-node.js +59 -0
  46. package/cjs/node/serveStatic.js +56 -0
  47. package/cjs/node/toWebRequest.js +25 -0
  48. package/cjs/node/ws.js +82 -0
  49. package/cjs/registry/RadixRouter.js +148 -0
  50. package/cjs/registry/index.js +17 -0
  51. package/cjs/types/headers.js +2 -0
  52. package/cjs/types/index.js +13 -0
  53. package/cjs/utils/buffer.js +17 -0
  54. package/cjs/utils/colors.js +2 -0
  55. package/cjs/utils/cookie.js +59 -0
  56. package/cjs/utils/file.js +136 -0
  57. package/cjs/utils/formData.js +60 -10
  58. package/cjs/utils/generateID.js +37 -0
  59. package/cjs/utils/low-level.js +115 -0
  60. package/cjs/utils/{staticFile.js → mimeTypes.js} +0 -87
  61. package/cjs/utils/rateLimit.js +41 -0
  62. package/cjs/utils/response.js +65 -0
  63. package/cjs/{core/environment.js → utils/runtime.js} +2 -1
  64. package/cjs/utils/url.js +65 -30
  65. package/core/config.d.ts +2 -7
  66. package/core/config.js +2 -12
  67. package/core/context.d.ts +209 -164
  68. package/core/context.js +131 -346
  69. package/core/error.d.ts +96 -0
  70. package/core/error.js +44 -0
  71. package/core/request.d.ts +67 -107
  72. package/core/request.js +78 -130
  73. package/core/router.d.ts +138 -133
  74. package/core/router.js +53 -352
  75. package/core/server.d.ts +99 -38
  76. package/core/server.js +83 -202
  77. package/deno/env.js +3 -3
  78. package/deno/getConnInfo.d.ts +21 -0
  79. package/deno/getConnInfo.js +15 -0
  80. package/deno/index.d.ts +9 -4
  81. package/deno/index.js +7 -4
  82. package/deno/serveStatic.d.ts +28 -0
  83. package/deno/serveStatic.js +49 -0
  84. package/deno/ws.d.ts +42 -0
  85. package/deno/ws.js +36 -0
  86. package/helper/index.d.ts +29 -15
  87. package/helper/index.js +27 -7
  88. package/index.d.ts +10 -8
  89. package/index.js +4 -5
  90. package/jwt/node.d.ts +39 -0
  91. package/jwt/node.js +87 -0
  92. package/jwt/web.d.ts +14 -0
  93. package/jwt/web.js +174 -0
  94. package/middleware/basic-auth.d.ts +56 -0
  95. package/middleware/basic-auth.js +38 -0
  96. package/middleware/bearer-auth.d.ts +53 -0
  97. package/middleware/bearer-auth.js +30 -0
  98. package/middleware/cache-control.d.ts +30 -0
  99. package/middleware/cache-control.js +40 -0
  100. package/middleware/cors.d.ts +30 -3
  101. package/middleware/cors.js +12 -22
  102. package/middleware/detect-bot.d.ts +113 -0
  103. package/middleware/detect-bot.js +53 -0
  104. package/middleware/i18n.d.ts +166 -73
  105. package/middleware/i18n.js +73 -60
  106. package/middleware/index.d.ts +8 -32
  107. package/middleware/index.js +8 -44
  108. package/middleware/logger.d.ts +5 -2
  109. package/middleware/logger.js +9 -4
  110. package/middleware/pagination.d.ts +9 -6
  111. package/middleware/pagination.js +3 -2
  112. package/middleware/powered-by.d.ts +2 -1
  113. package/middleware/powered-by.js +3 -2
  114. package/middleware/{rateLimiter.d.ts → rate-limiter.d.ts} +15 -9
  115. package/middleware/rate-limiter.js +34 -0
  116. package/middleware/request-id.d.ts +2 -1
  117. package/middleware/request-id.js +5 -6
  118. package/middleware/{sanitizeHeader.d.ts → sanitize-headers.d.ts} +5 -19
  119. package/middleware/sanitize-headers.js +18 -0
  120. package/middleware/secure-headers copy.d.ts +15 -0
  121. package/middleware/secure-headers copy.js +136 -0
  122. package/middleware/secure-headers.d.ts +132 -0
  123. package/middleware/secure-headers.js +153 -0
  124. package/middleware/{xssProtection.d.ts → xss-protection.d.ts} +2 -1
  125. package/middleware/xss-protection.js +19 -0
  126. package/node/env.js +4 -4
  127. package/node/getConnInfo.d.ts +21 -0
  128. package/node/getConnInfo.js +13 -0
  129. package/node/index.d.ts +13 -4
  130. package/node/index.js +11 -4
  131. package/node/mount-node.d.ts +11 -0
  132. package/node/mount-node.js +56 -0
  133. package/node/serveStatic.d.ts +36 -0
  134. package/node/serveStatic.js +52 -0
  135. package/node/toWebRequest.js +22 -0
  136. package/node/ws.d.ts +56 -0
  137. package/node/ws.js +46 -0
  138. package/package.json +39 -30
  139. package/registry/RadixRouter.d.ts +40 -0
  140. package/registry/RadixRouter.js +144 -0
  141. package/registry/index.d.ts +2 -0
  142. package/registry/index.js +1 -0
  143. package/types/headers.d.ts +2 -0
  144. package/types/headers.js +1 -0
  145. package/types/index.d.ts +318 -18
  146. package/types/index.js +12 -1
  147. package/utils/buffer.d.ts +1 -0
  148. package/utils/buffer.js +14 -0
  149. package/utils/colors.d.ts +24 -0
  150. package/utils/colors.js +2 -0
  151. package/utils/cookie.d.ts +55 -0
  152. package/utils/cookie.js +53 -0
  153. package/utils/file.d.ts +38 -0
  154. package/utils/file.js +96 -0
  155. package/utils/formData.d.ts +41 -1
  156. package/utils/formData.js +58 -9
  157. package/utils/generateID.d.ts +42 -0
  158. package/utils/generateID.js +32 -0
  159. package/utils/httpStatusMap.d.ts +14 -0
  160. package/utils/low-level.d.ts +58 -0
  161. package/utils/low-level.js +108 -0
  162. package/utils/mimeTypes.d.ts +4 -0
  163. package/utils/{staticFile.js → mimeTypes.js} +0 -53
  164. package/utils/rateLimit.d.ts +18 -0
  165. package/utils/rateLimit.js +37 -0
  166. package/utils/response.d.ts +18 -0
  167. package/utils/response.js +58 -0
  168. package/{core/environment.d.ts → utils/runtime.d.ts} +1 -0
  169. package/{core/environment.js → utils/runtime.js} +1 -0
  170. package/utils/url.d.ts +42 -14
  171. package/utils/url.js +61 -27
  172. package/bun/adapter.d.ts +0 -127
  173. package/bun/adapter.js +0 -97
  174. package/cjs/bun/adapter.js +0 -100
  175. package/cjs/core/MiddlewareConfigure.js +0 -68
  176. package/cjs/core/common.js +0 -15
  177. package/cjs/deno/adpater.js +0 -67
  178. package/cjs/helper/common.js +0 -17
  179. package/cjs/middleware/basicAuth.js +0 -71
  180. package/cjs/middleware/cacheControl.js +0 -90
  181. package/cjs/middleware/detectBot.js +0 -104
  182. package/cjs/middleware/detectLocale.js +0 -43
  183. package/cjs/middleware/lazyLoadModules.js +0 -73
  184. package/cjs/middleware/rateLimiter.js +0 -24
  185. package/cjs/middleware/requestTimeout.js +0 -42
  186. package/cjs/middleware/sanitizeHeader.js +0 -51
  187. package/cjs/middleware/secureHeaders.js +0 -42
  188. package/cjs/node/adapter.js +0 -138
  189. package/cjs/utils/regexRouter.js +0 -58
  190. package/cjs/utils/state.js +0 -34
  191. package/cjs/utils/toWebRequest.js +0 -35
  192. package/cjs/ws/deno.js +0 -20
  193. package/cjs/ws/index.js +0 -53
  194. package/cjs/ws/node.js +0 -65
  195. package/core/MiddlewareConfigure.d.ts +0 -15
  196. package/core/MiddlewareConfigure.js +0 -63
  197. package/core/common.d.ts +0 -21
  198. package/core/common.js +0 -11
  199. package/deno/adpater.d.ts +0 -38
  200. package/deno/adpater.js +0 -64
  201. package/helper/common.d.ts +0 -5
  202. package/helper/common.js +0 -14
  203. package/middleware/basicAuth.d.ts +0 -81
  204. package/middleware/basicAuth.js +0 -67
  205. package/middleware/cacheControl.d.ts +0 -48
  206. package/middleware/cacheControl.js +0 -53
  207. package/middleware/detectBot.d.ts +0 -121
  208. package/middleware/detectBot.js +0 -98
  209. package/middleware/detectLocale.d.ts +0 -55
  210. package/middleware/detectLocale.js +0 -39
  211. package/middleware/lazyLoadModules.d.ts +0 -72
  212. package/middleware/lazyLoadModules.js +0 -69
  213. package/middleware/rateLimiter.js +0 -20
  214. package/middleware/requestTimeout.d.ts +0 -25
  215. package/middleware/requestTimeout.js +0 -38
  216. package/middleware/sanitizeHeader.js +0 -47
  217. package/middleware/secureHeaders.d.ts +0 -78
  218. package/middleware/secureHeaders.js +0 -38
  219. package/middleware/xssProtection.js +0 -22
  220. package/node/adapter.d.ts +0 -46
  221. package/node/adapter.js +0 -102
  222. package/utils/regexRouter.d.ts +0 -66
  223. package/utils/regexRouter.js +0 -53
  224. package/utils/state.d.ts +0 -50
  225. package/utils/state.js +0 -30
  226. package/utils/staticFile.d.ts +0 -10
  227. package/utils/toWebRequest.js +0 -32
  228. package/ws/deno.d.ts +0 -6
  229. package/ws/deno.js +0 -16
  230. package/ws/index.d.ts +0 -180
  231. package/ws/index.js +0 -50
  232. package/ws/node.d.ts +0 -7
  233. package/ws/node.js +0 -28
  234. /package/{utils → node}/toWebRequest.d.ts +0 -0
@@ -1,69 +0,0 @@
1
- import { GlobalConfig } from "../core/config.js";
2
- export const lazyLoadModules = (options) => {
3
- const { moduleKey = (ctx) => ctx.req.params[queryKeyModule] || ctx.req.query[queryKeyModule], getModuleLoader, queryKeyModule = "module", moduleContextKey = "module", cacheTTL = 3600000, enableCache = true, cacheStorage, lifecycleHooks = {}, validateModule, } = options;
4
- let storage = cacheStorage;
5
- if (enableCache && !cacheStorage) {
6
- storage = new Map();
7
- }
8
- return async function lazyLoadModules(ctx, next) {
9
- let moduleName = moduleKey(ctx) ||
10
- ctx.req.params[queryKeyModule] ||
11
- ctx.req.query[queryKeyModule];
12
- if (!moduleName) {
13
- GlobalConfig.debugging.warn("No module specified for lazy loading.");
14
- return await next();
15
- }
16
- try {
17
- if (enableCache) {
18
- const cached = storage.get(moduleName);
19
- if (cached) {
20
- if (cached.expiresAt < Date.now()) {
21
- storage.delete(moduleName);
22
- }
23
- else {
24
- GlobalConfig.debugging.info(`Using cached module: ${moduleName}`);
25
- ctx[moduleContextKey] = cached?.module;
26
- lifecycleHooks.onCacheHit?.(moduleName, ctx[moduleContextKey], ctx);
27
- lifecycleHooks.onComplete?.(moduleName, ctx[moduleContextKey], ctx);
28
- return await next();
29
- }
30
- }
31
- }
32
- if (!getModuleLoader) {
33
- throw new Error(`No module loader found for module: ${moduleName}`);
34
- }
35
- const moduleLoader = await getModuleLoader(ctx);
36
- if (!moduleLoader) {
37
- throw new Error(`No loader found for module: ${moduleName}`);
38
- }
39
- lifecycleHooks.onLoad?.(moduleName, ctx);
40
- const module = await moduleLoader();
41
- if (validateModule && !validateModule(module)) {
42
- throw new Error(`Module validation failed for: ${moduleName}`);
43
- }
44
- if (enableCache) {
45
- storage.set(moduleName, {
46
- module,
47
- expiresAt: Date.now() + cacheTTL,
48
- });
49
- lifecycleHooks.onCacheSet?.(moduleName, module, ctx);
50
- }
51
- ctx[moduleContextKey] = module;
52
- if (module.init && typeof module.init === "function") {
53
- const initResult = await module.init(ctx);
54
- if (initResult) {
55
- return initResult;
56
- }
57
- }
58
- lifecycleHooks.onComplete?.(moduleName, module, ctx);
59
- GlobalConfig.debugging.success(`Successfully loaded module: ${moduleName}`);
60
- }
61
- catch (error) {
62
- GlobalConfig.debugging.error(`Error loading module: ${moduleName}`, error);
63
- lifecycleHooks.onError?.(moduleName, error, ctx);
64
- ctx.setStatus = 500;
65
- throw error;
66
- }
67
- return await next();
68
- };
69
- };
@@ -1,20 +0,0 @@
1
- import { createRateLimitDefaultStorage, isRateLimit } from "./detectBot.js";
2
- export const rateLimiter = (options) => {
3
- const { maxRequests, windowMs, keyGenerator = (ctx) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, storage = createRateLimitDefaultStorage(), onError = (ctx, retryAfter, error) => {
4
- ctx.setStatus = 429;
5
- throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
6
- }, } = options;
7
- return async function rateLimiter(ctx, next) {
8
- const key = keyGenerator(ctx);
9
- const { check, entry } = isRateLimit(ctx, key, storage, maxRequests, windowMs);
10
- if (check) {
11
- const retryAfter = Math.ceil((entry.resetTime - Date.now()) / 1000);
12
- ctx.headers.set("Retry-After", retryAfter.toString());
13
- return onError(ctx, retryAfter, new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`));
14
- }
15
- ctx.headers.set("X-RateLimit-Limit", maxRequests.toString());
16
- ctx.headers.set("X-RateLimit-Remaining", (maxRequests - entry.count).toString());
17
- ctx.headers.set("X-RateLimit-Reset", entry.resetTime.toString());
18
- return await next();
19
- };
20
- };
@@ -1,25 +0,0 @@
1
- import { Context } from "../core/context.js";
2
- import { CallbackReturn, Middleware } from "../types/index.js";
3
- export type TimeoutOptions = {
4
- /**
5
- * ⏳ Function to dynamically determine the timeout duration (in milliseconds).
6
- */
7
- getTimeout: (ctx: Context) => number;
8
- /**
9
- * 🚫 Custom function to handle timeout errors.
10
- */
11
- onTimeout?: (ctx: Context, error: Error) => CallbackReturn;
12
- /**
13
- * 📝 Logging function for timeout events.
14
- */
15
- logTimeoutEvent?: (ctx: Context, error: Error) => void;
16
- /**
17
- * 🛠️ Custom function to clean up resources after a timeout.
18
- */
19
- cleanup?: (ctx: Context) => void;
20
- };
21
- /**
22
- * Middleware to enforce fully dynamic request timeouts.
23
- * @param options - Custom options for dynamic timeout handling.
24
- */
25
- export declare const requestTimeout: (options: TimeoutOptions) => Middleware;
@@ -1,38 +0,0 @@
1
- import { GlobalConfig } from "../core/config.js";
2
- export const requestTimeout = (options) => {
3
- const { getTimeout, onTimeout = (ctx) => {
4
- ctx.setStatus = 504;
5
- ctx.body = { error: "Request timed out." };
6
- }, logTimeoutEvent = (ctx, error) => {
7
- GlobalConfig.debugging.warn(`[TIMEOUT] ${error.message}: ${ctx.method} ${ctx.path}`);
8
- }, cleanup = () => {
9
- }, } = options;
10
- return async function requestTimeout(ctx, next) {
11
- let timeoutId = null;
12
- try {
13
- const timeout = getTimeout(ctx);
14
- const timeoutPromise = new Promise((_, reject) => {
15
- timeoutId = setTimeout(() => {
16
- const timeoutError = new Error("Request timed out.");
17
- logTimeoutEvent(ctx, timeoutError);
18
- reject(timeoutError);
19
- }, timeout);
20
- });
21
- return await Promise.race([next(), timeoutPromise]);
22
- }
23
- catch (error) {
24
- if (error.message === "Request timed out.") {
25
- onTimeout(ctx, error);
26
- }
27
- else {
28
- throw error;
29
- }
30
- }
31
- finally {
32
- if (timeoutId) {
33
- clearTimeout(timeoutId);
34
- }
35
- cleanup(ctx);
36
- }
37
- };
38
- };
@@ -1,47 +0,0 @@
1
- import { GlobalConfig } from "../core/config.js";
2
- export const sanitizeHeaders = (options = {}) => {
3
- const { whitelist = [], blacklist = [], normalizeKeys = true, allowUnsafeCharacters = false, } = options;
4
- return async function sanitizeHeaders(ctx, next) {
5
- const sanitizedHeaders = new Map();
6
- for (const [key, values] of ctx.headers.entries()) {
7
- if (!Array.isArray(values) || values.length === 0) {
8
- continue;
9
- }
10
- const normalizedKey = normalizeKeys ? key.toLowerCase() : key;
11
- if (whitelist.length > 0 &&
12
- !whitelist.some((r) => r?.toLowerCase() === normalizedKey)) {
13
- GlobalConfig.debugging.warn(`🚫 Header "${normalizedKey}" not in whitelist - removed`);
14
- continue;
15
- }
16
- if (blacklist.some((r) => r.toLowerCase() === normalizedKey)) {
17
- GlobalConfig.debugging.warn(`🚫 Header "${normalizedKey}" in blacklist - removed`);
18
- continue;
19
- }
20
- if (!isValidHeaderName(normalizedKey)) {
21
- GlobalConfig.debugging.warn(`⚠️ Invalid header name: "${normalizedKey}" - removed`);
22
- continue;
23
- }
24
- const sanitizedValues = values
25
- .map((value) => sanitizeHeaderValue(value, allowUnsafeCharacters))
26
- .filter(Boolean);
27
- if (sanitizedValues.length === 0) {
28
- GlobalConfig.debugging.warn(`⚠️ All values for "${normalizedKey}" invalid - removed`);
29
- continue;
30
- }
31
- sanitizedHeaders.set(normalizedKey, sanitizedValues?.join(", "));
32
- }
33
- ctx.headers = new Headers(sanitizedHeaders);
34
- return await next();
35
- };
36
- };
37
- const isValidHeaderName = (name) => {
38
- const HEADER_NAME_REGEX = /^[a-zA-Z0-9\-_]+$/;
39
- return HEADER_NAME_REGEX.test(name);
40
- };
41
- const sanitizeHeaderValue = (value, allowUnsafeCharacters) => {
42
- let sanitized = value.trim();
43
- if (!allowUnsafeCharacters) {
44
- sanitized = sanitized.replace(/[\x00-\x1F\x7F]/g, "");
45
- }
46
- return sanitized;
47
- };
@@ -1,78 +0,0 @@
1
- import { Context } from "../core/context.js";
2
- import { Middleware } from "../types/index.js";
3
- export type DynamicHeaderValue = string | ((ctx: Context) => string | undefined);
4
- export type SecurityHeaderOptions = {
5
- /**
6
- * 🔵 Content Security Policy header value
7
- * @default "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
8
- * @example
9
- * contentSecurityPolicy: "default-src 'none'; script-src 'self' https://trusted.cdn.com"
10
- * contentSecurityPolicy: (ctx) => ctx.isAdmin ? "default-src 'self'" : "default-src 'none'"
11
- */
12
- contentSecurityPolicy?: DynamicHeaderValue;
13
- /**
14
- * 🟢 Whether to set X-Frame-Options header (clickjacking protection)
15
- * @default true
16
- * @example
17
- * frameGuard: true // Always enable
18
- * frameGuard: (ctx) => !ctx.pathname.startsWith('/embed/') // Disable for embed routes
19
- */
20
- frameGuard?: boolean | ((ctx: Context) => boolean);
21
- /**
22
- * 🟣 HTTP Strict Transport Security (HSTS) header
23
- * @default true
24
- * @example
25
- * hsts: true // Enable with 2 year duration
26
- * hsts: (ctx) => ctx.secure // Enable only for HTTPS
27
- */
28
- hsts?: boolean | ((ctx: Context) => boolean);
29
- /**
30
- * 🟠 XSS Protection header
31
- * @default true
32
- * @example
33
- * xssProtection: false // Disable legacy XSS filter
34
- */
35
- xssProtection?: boolean | ((ctx: Context) => boolean);
36
- /**
37
- * 🟡 X-Content-Type-Options header (MIME sniffing prevention)
38
- * @default true
39
- * @example
40
- * noSniff: false // Only disable if you have specific needs
41
- */
42
- noSniff?: boolean | ((ctx: Context) => boolean);
43
- /**
44
- * 🔴 Referrer Policy header
45
- * @default "no-referrer"
46
- * @example
47
- * referrerPolicy: "strict-origin-when-cross-origin"
48
- */
49
- referrerPolicy?: DynamicHeaderValue;
50
- /**
51
- * 🟤 Permissions Policy header (formerly Feature Policy)
52
- * @default "geolocation=(), microphone=(), camera=()"
53
- * @example
54
- * permissionsPolicy: "geolocation=(self 'https://example.com')"
55
- */
56
- permissionsPolicy?: DynamicHeaderValue;
57
- };
58
- /**
59
- * 🛡️ Comprehensive security headers middleware
60
- *
61
- * Sets multiple security-related HTTP headers with dynamic configuration.
62
- * All headers can be configured per-request using functions.
63
- *
64
- * @param {SecurityHeaderOptions} [options={}] - Configuration options
65
- * @returns {Middleware} Middleware function
66
- *
67
- * @example
68
- * // Basic usage with defaults
69
- * app.use(secureHeaders());
70
- *
71
- * // Custom configuration
72
- * app.use(secureHeaders({
73
- * contentSecurityPolicy: "default-src 'self'",
74
- * frameGuard: (ctx) => !ctx.isEmbedded,
75
- * referrerPolicy: "strict-origin-when-cross-origin"
76
- * }));
77
- */
78
- export declare const secureHeaders: (options?: SecurityHeaderOptions) => Middleware;
@@ -1,38 +0,0 @@
1
- export const secureHeaders = (options = {}) => {
2
- return async function secureHeaders(ctx, next) {
3
- const resolveValue = (value) => {
4
- return typeof value === "function" ? value(ctx) : value;
5
- };
6
- const contentSecurityPolicy = resolveValue(options.contentSecurityPolicy) ||
7
- "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';";
8
- const frameGuard = resolveValue(options.frameGuard) ?? true;
9
- const hsts = resolveValue(options.hsts) ?? true;
10
- const xssProtection = resolveValue(options.xssProtection) ?? true;
11
- const noSniff = resolveValue(options.noSniff) ?? true;
12
- const referrerPolicy = resolveValue(options.referrerPolicy) || "no-referrer";
13
- const permissionsPolicy = resolveValue(options.permissionsPolicy) ||
14
- "geolocation=(), microphone=(), camera=()";
15
- if (contentSecurityPolicy) {
16
- ctx.headers.set("Content-Security-Policy", contentSecurityPolicy);
17
- }
18
- if (frameGuard) {
19
- ctx.headers.set("X-Frame-Options", "DENY");
20
- }
21
- if (hsts) {
22
- ctx.headers.set("Strict-Transport-Security", "max-age=63072000; includeSubDomains");
23
- }
24
- if (xssProtection) {
25
- ctx.headers.set("X-XSS-Protection", "1; mode=block");
26
- }
27
- if (noSniff) {
28
- ctx.headers.set("X-Content-Type-Options", "nosniff");
29
- }
30
- if (referrerPolicy) {
31
- ctx.headers.set("Referrer-Policy", referrerPolicy);
32
- }
33
- if (permissionsPolicy) {
34
- ctx.headers.set("Permissions-Policy", permissionsPolicy);
35
- }
36
- return await next();
37
- };
38
- };
@@ -1,22 +0,0 @@
1
- import { GlobalConfig } from "../core/config.js";
2
- export const xssProtection = (options = {}) => {
3
- const { enabled = true, mode = "block", fallbackCSP = "default-src 'self'; script-src 'self';", } = options;
4
- return async function xssProtection(ctx, next) {
5
- const isEnabled = typeof enabled === "function" ? enabled(ctx) : enabled;
6
- if (!isEnabled) {
7
- GlobalConfig.debugging.warn("🟠 XSS protection is disabled.");
8
- return await next();
9
- }
10
- const xssHeaderValue = mode === "block" ? "1; mode=block" : "1";
11
- ctx.headers.set("X-XSS-Protection", xssHeaderValue);
12
- GlobalConfig.debugging.warn(`🟢 X-XSS-Protection set to: ${xssHeaderValue}`);
13
- if (fallbackCSP) {
14
- const existingCSP = ctx.req.headers.get("Content-Security-Policy");
15
- if (!existingCSP) {
16
- ctx.headers.set("Content-Security-Policy", fallbackCSP);
17
- GlobalConfig.debugging.warn(`🟣 Fallback CSP set to: ${fallbackCSP}`);
18
- }
19
- }
20
- return await next();
21
- };
22
- };
package/node/adapter.d.ts DELETED
@@ -1,46 +0,0 @@
1
- import type { ServerOptions } from "node:http";
2
- import type { TlsOptions } from "node:tls";
3
- import { TezX } from "../core/server.js";
4
- export type UnixSocketOptions = ServerOptions & {
5
- unix?: string;
6
- enableSSL?: false;
7
- };
8
- export type SSLOptions = ServerOptions & TlsOptions & {
9
- enableSSL: true;
10
- };
11
- export type TezXServerOptions = UnixSocketOptions | SSLOptions;
12
- /**
13
- * Starts the TezX server using Node.js native `http` or `https` module based on the `enableSSL` flag.
14
- * - If `enableSSL` is true and valid TLS options are provided, it uses `https.createServer`.
15
- * - Otherwise, falls back to `http.createServer`.
16
- * - Optionally supports binding to a Unix domain socket via `options.unix`.
17
- *
18
- * ### Usage:
19
- *
20
- * ```ts
21
- * // Start with default HTTP
22
- * nodeAdapter(app).listen(3000, () => {
23
- * console.log("Server is running");
24
- * });
25
- *
26
- * // Start with HTTPS
27
- * nodeAdapter(app, {
28
- * enableSSL: true,
29
- * key: fs.readFileSync("key.pem"),
30
- * cert: fs.readFileSync("cert.pem")
31
- * }).listen(443);
32
- *
33
- * // Start with Unix socket
34
- * nodeAdapter(app, { unix: "/tmp/tezx.sock" }).listen();
35
- * ```
36
- * @param {number} [port] - The port number to listen on (ignored if `unix` is provided).
37
- * @param {() => void} [callback] - Callback invoked after the server starts listening.
38
- * @returns {void} Nothing is returned directly; server instance is stored in GlobalConfig.
39
- */
40
- export declare function nodeAdapter<T extends Record<string, any> = {}>(TezX: TezX<T>, options?: TezXServerOptions): {
41
- listen: {
42
- (callback?: () => void): any;
43
- (port?: number): any;
44
- (port?: number, callback?: () => void): any;
45
- };
46
- };
package/node/adapter.js DELETED
@@ -1,102 +0,0 @@
1
- import { Buffer } from "node:buffer";
2
- import { createServer } from "node:http";
3
- import { createServer as sslCreateServer } from "node:https";
4
- import { GlobalConfig } from "../core/config.js";
5
- import { Context } from "../core/context.js";
6
- export function nodeAdapter(TezX, options = {}) {
7
- function listen(...arg) {
8
- let ssl = options?.enableSSL;
9
- let createServerFn = ssl ? sslCreateServer : createServer;
10
- GlobalConfig.adapter = "node";
11
- let server = createServerFn(options, async (req, res) => {
12
- let address = {};
13
- if (req.socket) {
14
- address = {
15
- remoteAddr: {
16
- family: req.socket.remoteFamily,
17
- address: req.socket.remoteAddress,
18
- port: req.socket.remotePort,
19
- },
20
- localAddr: {
21
- address: req.socket.localAddress,
22
- port: req.socket.localPort,
23
- family: req.socket.localFamily,
24
- },
25
- };
26
- }
27
- let options = {
28
- connInfo: address,
29
- };
30
- const response = await TezX.serve(req, options);
31
- if (typeof response?.websocket === "function" &&
32
- response.ctx instanceof Context &&
33
- response.ctx.wsProtocol) {
34
- response.websocket(response.ctx, server);
35
- return res.end();
36
- }
37
- const statusText = response?.statusText;
38
- if (!(response instanceof Response)) {
39
- throw new Error("Invalid response from TezX.serve");
40
- }
41
- if (statusText) {
42
- res.statusMessage = statusText;
43
- }
44
- res.writeHead(response.status, [...response.headers.entries()]);
45
- const { Readable } = await import("node:stream");
46
- const body = response.body;
47
- if (response.headers.get("Content-Type") === "text/event-stream") {
48
- req.socket.setTimeout(0);
49
- }
50
- if (body instanceof Readable) {
51
- return body.pipe(res);
52
- }
53
- else if (body?.pipeTo || body?.getReader) {
54
- try {
55
- return Readable.fromWeb(body).pipe(res);
56
- }
57
- catch (err) {
58
- GlobalConfig.debugging.warn("Failed to stream web body:", err);
59
- return res.end();
60
- }
61
- }
62
- else if (typeof body?.[Symbol.asyncIterator] === "function") {
63
- const readable = Readable.from(body);
64
- return readable.pipe(res);
65
- }
66
- else {
67
- try {
68
- const buffer = await response.arrayBuffer?.();
69
- if (buffer && buffer.byteLength > 0) {
70
- return res.end(Buffer.from(buffer));
71
- }
72
- else {
73
- return res.end();
74
- }
75
- }
76
- catch (err) {
77
- GlobalConfig.debugging.warn("Body extraction failed, trying text fallback...");
78
- const text = await response.text?.();
79
- return res.end(text ?? "");
80
- }
81
- }
82
- });
83
- const port = typeof arg[0] === "function" ? undefined : arg[0];
84
- const callback = typeof arg[0] === "function" ? arg[0] : arg[1];
85
- server.listen(options?.unix || port || 0, () => {
86
- const protocol = ssl ? "\x1b[1;35mhttps\x1b[0m" : "\x1b[1;34mhttp\x1b[0m";
87
- const address = server.address();
88
- const message = typeof address === "string"
89
- ? `\x1b[1mNodeJS TezX Server running at unix://${address}\x1b[0m`
90
- : `\x1b[1mNodeJS TezX Server running at ${protocol}://localhost:${address?.port}/\x1b[0m`;
91
- GlobalConfig.server = server;
92
- GlobalConfig.debugging.success(message);
93
- if (typeof callback == "function")
94
- callback();
95
- return server;
96
- });
97
- return server;
98
- }
99
- return {
100
- listen,
101
- };
102
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Compiles a route string or segment array into a regular expression for matching URL paths.
3
- * Supports dynamic `:param`, optional `:param?`, and wildcard `*param` segments.
4
- *
5
- * @param {string | string[]} seg - The route pattern, either as a string (`'/user/:id'`)
6
- * or an array of segments (`['user', ':id']`).
7
- *
8
- * @returns {{
9
- * regex: RegExp,
10
- * paramNames: string[]
11
- * }}
12
- * @example
13
- * const { regex, paramNames } = compileRegexRoute('/user/:id/post/:slug?');
14
- * // regex: /^\/user\/([^\/]+)\/(?:([^\/]+))?\/?$/
15
- * // paramNames: ['id', 'slug']
16
- *
17
- * regex.test('/user/123/post/hello'); // ✅ true
18
- * regex.test('/user/123/post'); // ✅ true (because :slug? is optional)
19
- *
20
- * @example
21
- * const { regex, paramNames } = compileRegexRoute('/files/*path');
22
- * // regex: /^\/files\/(.+)\/?$/
23
- * // paramNames: ['path']
24
- *
25
- * regex.test('/files/images/cat.jpg'); // ✅ true
26
- */
27
- export declare function compileRegexRoute(seg: string | string[]): {
28
- regex: RegExp;
29
- paramNames: string[];
30
- };
31
- /**
32
- * Combines a base path with a route regex pattern.
33
- *
34
- * @param basePath - The base path to prepend (e.g., '/api/v1')
35
- * @param routeRegex - The original route regex (e.g., /^\/users\/([^/]+?)$/)
36
- * @returns A new regex that includes the base path
37
- */
38
- export declare function addBaseToRegex(basePath: string, routeRegex: RegExp): RegExp;
39
- /**
40
- * Matches a given URL against a provided regular expression and extracts named parameters.
41
- *
42
- * @param {RegExp} regex - The regular expression to match against the URL.
43
- * It should include capturing groups for each parameter.
44
- * Example: /^\/user\/(\d+)\/post\/(\w+)$/
45
- *
46
- * @param {string} url - The URL string to match.
47
- * Example: "/user/123/post/abc"
48
- *
49
- * @param {string[]} paramNames - An array of parameter names corresponding to the capturing groups in the regex.
50
- * Example: ["userId", "postId"]
51
- *
52
- * @returns {{ success: boolean, params: Record<string, string | null> }} An object indicating:
53
- * - `success`: whether the URL matched the regex.
54
- * - `params`: an object mapping parameter names to their matched values, or `null` if not found.
55
- *
56
- * @example
57
- * const regex = /^\/user\/(\d+)\/post\/(\w+)$/;
58
- * const url = "/user/123/post/abc";
59
- * const paramNames = ["userId", "postId"];
60
- * const result = regexMatchRoute(regex, url, paramNames);
61
- * // result = { success: true, params: { userId: "123", postId: "abc" } }
62
- */
63
- export declare function regexMatchRoute(regex: RegExp, url: string, paramNames?: string[]): {
64
- params: Record<string, string | null>;
65
- success: boolean;
66
- };
@@ -1,53 +0,0 @@
1
- import { sanitizePathSplit } from "./url.js";
2
- export function compileRegexRoute(seg) {
3
- const segments = typeof seg == 'string' ? seg.split("/").filter(Boolean) : seg;
4
- let regexStr = "^";
5
- const paramNames = [];
6
- for (let seg of segments) {
7
- if (seg.startsWith(":")) {
8
- const isOptional = seg.endsWith("?");
9
- const name = seg.replace(":", "").replace("?", "");
10
- paramNames.push(name);
11
- regexStr += isOptional
12
- ? `(?:\\/([^\\/]+))?`
13
- : `\\/([^\\/]+)`;
14
- }
15
- else if (seg.startsWith("*")) {
16
- const name = seg.slice(1) || "*";
17
- paramNames.push(name);
18
- regexStr += `\\/(.+)`;
19
- }
20
- else {
21
- regexStr += `\\/${seg}`;
22
- }
23
- }
24
- regexStr += "\\/?$";
25
- return {
26
- regex: new RegExp(regexStr),
27
- paramNames,
28
- };
29
- }
30
- export function addBaseToRegex(basePath, routeRegex) {
31
- basePath = "/" + sanitizePathSplit("/", basePath)?.join("/");
32
- if (basePath === "/")
33
- basePath = "";
34
- let body = routeRegex.source.replace(/^(\^)/, '').replace(/(\$)$/, '');
35
- body = body.replace(/\\\//g, "/");
36
- if (body.startsWith("/")) {
37
- body = body.slice(1);
38
- }
39
- const cleaned = body.replace(/^\/+|\/+$/g, "").replace(/\/?\?$/, "");
40
- const combined = basePath + "/" + cleaned + "/?";
41
- const finalRegex = new RegExp(`^${combined}$`);
42
- return finalRegex;
43
- }
44
- export function regexMatchRoute(regex, url, paramNames = []) {
45
- const match = url.match(regex);
46
- if (!match)
47
- return { success: false, params: {} };
48
- const params = {};
49
- paramNames.forEach((name, idx) => {
50
- params[name] = match[idx + 1] ?? null;
51
- });
52
- return { params, success: true };
53
- }
package/utils/state.d.ts DELETED
@@ -1,50 +0,0 @@
1
- /**
2
- * A simple key-value storage class using Map.
3
- */
4
- export declare class State {
5
- private state;
6
- constructor();
7
- /**
8
- * Store a value with a specific key.
9
- * @param key - The key for the value.
10
- * @param value - The value to be stored.
11
- */
12
- set(key: string, value: any): void;
13
- /**
14
- * Retrieve a value by key.
15
- * @param key - The key of the value to retrieve.
16
- * @returns The stored value or undefined if not found.
17
- */
18
- get(key: string): any | undefined;
19
- /**
20
- * Delete a key from storage.
21
- * @param key - The key to remove.
22
- * @returns True if the key was deleted, false otherwise.
23
- */
24
- delete(key: string): boolean;
25
- /**
26
- * Check if a key exists in the storage.
27
- * @param key - The key to check.
28
- * @returns True if the key exists, false otherwise.
29
- */
30
- has(key: string): boolean;
31
- /**
32
- * Get an array of all stored keys.
33
- * @returns An array of keys.
34
- */
35
- keys(): string[];
36
- /**
37
- * Get an array of all stored values.
38
- * @returns An array of values.
39
- */
40
- values(): any[];
41
- /**
42
- * Get an array of all key-value pairs.
43
- * @returns An array of [key, value] tuples.
44
- */
45
- entries(): [string, any][];
46
- /**
47
- * Remove all entries from storage.
48
- */
49
- clear(): void;
50
- }